home *** CD-ROM | disk | FTP | other *** search
/ Aminet 4 / Aminet 4 - November 1994.iso / aminet / comm / misc / newser221.lha / newser.asm next >
Assembly Source File  |  1993-07-10  |  72KB  |  2,984 lines

  1. *****************************************************************************
  2. * NEWSER.ASM -- a "serial.device" compatible driver for the Rockwell 65C52
  3. *
  4. * Copyright © 1990-92 by Dan Babcock
  5. *
  6. * Permission is given for PERSONAL use of this code. Commercial
  7. * use is of course forbidden. (Without prior permission etc.)
  8. *
  9. * History:  08/12/90 V0.50 Created
  10. *           09/06/90 V0.51 Cleaned up "eofdump" code.
  11. *           11/04/90 V0.52 Misc. minor changes
  12. *                          [release 1]
  13. *           03/03/91 V1.10 Fixed some bugs, speeded up, & added prefs hook
  14. *           03/08/91 V1.11 Bug fixes
  15. *                          [release 2]
  16. *           04/18/91 V1.12 Small changes (very small)
  17. *           06/20/91 V2.00 Bug fixes, code clean-up, faster
  18. *                          [release 3]
  19. *           06/27/91 V2.10 Added ASDG-style DTR/RTS control extension
  20. *                          (See "SetControlLines" for documentaion)
  21. *                          Added special time-out to write routine to
  22. *                          avoid theoretical (and possibly real) problem
  23. *                          Fixed bug in Break routine
  24. *                          [release 4]
  25. *           07/03/91 V2.11 Minor optimizations
  26. *           07/29/91 V2.12 Minor bug fix in Read
  27. *           11/14/91 V2.13 Minor bug fix in Open
  28. *           07/04/92 V2.20 Fixed major bug in interrupt routine (symptom:
  29. *                          clicking on icon caused lock-up)
  30. *           09/26/92 V2.21 Fixed exclusive/shared logic in Open
  31. *
  32. * General notes
  33. * =============
  34. * The macro "PUTDEBUG" is used to output debugging information via the
  35. * internal serial port at a low level. It may be used anywhere, including
  36. * critical sections, supervisor mode, and interrupt code. If debugging is
  37. * not desired, set the INFO_LEVEL equate to zero. Conversely, if debugging
  38. * is desired, set it to a high value (e.g. 100000)
  39. *
  40. * A consistent (for the most part) usage of registers was employed:
  41. *  A1 - pointer to an IORequest structure
  42. *  A3 - pointer to a unit structure (defined below)
  43. *  A4 - pointer to a serprefs structure (defined below)
  44. *  A5 - pointer to the hardware (one channel, that is)
  45. *  A6 - pointer to the device structure (defined below)
  46. *
  47. * Known differences between this and serial.device are:
  48. *  1. Start/Stop do not send XON/XOFF characters to the outside world
  49. *     as implied in the autodoc. (I doubt anyone uses Start and Stop...)
  50. *  2. Newser does not currently send an XOFF or otherwise tell the outside
  51. *     world to "shut up" when the driver's input buffer fills.
  52. *     Since the buffer is 64K, it is very unlikely to ever fill.
  53. *  Both of those capabilities can be added external to the driver if you
  54. *  have a custom application that requires them.
  55. *****************************************************************************
  56.  
  57.     MC68010
  58.     super    ;suppress warnings about supervisor mode
  59.     exeobj
  60.     objfile    'devs:newser.device'
  61.     multipass
  62.  
  63. ;Set INFO_LEVEL to a high number (e.g. 100000) for full debugging output
  64. ;over the internal serial port.
  65. INFO_LEVEL    equ    000000
  66.  
  67. EXEC    macro
  68.     move.l    a1,-(sp)
  69.     move.l    a6,-(sp)
  70.     move.l    4,a6
  71.     jsr    (_LVO\1,a6)
  72.     move.l    (sp)+,a6
  73.     move.l    (sp)+,a1
  74.     endm
  75.  
  76. ;Put a message to the serial port.  Used like so:
  77. ;
  78. ;    PUTDEBUG   30,<'%s/Init: called'>
  79. ;
  80. ;Parameters can be printed out by pushing them on the stack and
  81. ;adding the appropriate C printf-style % formatting commands.
  82.  
  83. PUTDEBUG     macro        ;[level,msg]
  84.     ifge    INFO_LEVEL-\1
  85.     pea    (subSysName,pc)
  86.     movem.l    a0/a1/d0/d1,-(sp)
  87.     lea    (.msg\@,pc),a0    ;Point to static format string
  88.     lea    (4*4,sp),a1    ;Point to args
  89.     bsr    KPutFmt
  90.     movem.l    (sp)+,d0/d1/a0/a1
  91.     addq.l    #4,sp
  92.     bra.b    .end\@
  93.  
  94. .msg\@    cstr    \2,10
  95.     even
  96. .end\@
  97.     endc
  98.     endm
  99.  
  100. *** MACROS ***
  101.  
  102. ;Un-comment this if you need it!
  103. ;SYS    macro
  104. ;    jsr    (_LVO\1,a6)
  105. ;    endm
  106.  
  107.     IFND    _intena
  108. _intena    equ    _custom+intena
  109.     ENDC
  110.  
  111. Disable    macro
  112.     ifc    '\1',''
  113.     move.w    #INTF_INTEN,(_intena).l
  114.     move.l    a6,-(sp)
  115.     move.l    4,a6
  116.     addq.b    #1,(IDNestCnt,a6)
  117.     move.l    (sp)+,a6
  118.     endc
  119.     ifnc    '\1',''
  120.     move.l    4,\1
  121.     move.w    #INTF_INTEN,(_intena).l
  122.     addq.b    #1,(IDNestCnt,\1)
  123.     endc
  124.     endm
  125.  
  126. Enable    macro
  127.     ifc    '\1',''
  128.     move.l    a6,-(sp)
  129.     move.l    4,a6
  130.     subq.b    #1,(IDNestCnt,a6)
  131.     move.l    (sp)+,a6
  132.     bge.s    .Enable\#
  133.     move.w    #INTF_SETCLR!INTF_INTEN,(_intena).l
  134. .Enable\#
  135.     endc
  136.     ifnc    '\1',''
  137.     move.l    4,\1
  138.     subq.b    #1,(IDNestCnt,\1)
  139.     bge.s    .Enable\#
  140.     move.w    #INTF_SETCLR!INTF_INTEN,(_intena).l
  141. .Enable\#
  142.     endc
  143.     endm
  144.  
  145. Forbid    macro
  146.     move.l    a6,-(sp)
  147.     move.l    4,a6
  148.     addq.b    #1,(TDNestCnt,a6)
  149.     move.l    (sp)+,a6
  150.     endm
  151.  
  152. Permit    macro
  153.     movem.l    d0/d1/a0/a1/a6,-(sp)
  154.     move.l    4,a6
  155.     SYS    Permit
  156.     movem.l    (sp)+,d0/d1/a0/a1/a6
  157.     endm
  158.  
  159. ;*** EQUATES ***
  160.  
  161. MYPROCSTACKSIZE    equ    $900    ;Stack size for the task we will create
  162. MYPRI    equ    0    ;Used for configuring the roms
  163. VERSION    equ    1    ;A major version number.
  164. REVISION    equ    0    ;A particular revision
  165. MYDEV_END    equ    CMD_NONSTD+2    ;Number of device comands 
  166. MD_NUMUNITS    equ    4    ;Maximum number of units in this device
  167.  
  168. ;*** New SerialPrefs Structure ***
  169.  
  170. UnitPrefs    clrso
  171. up_BufSize    so.w    1    ;0 to 7
  172. up_BaudRate    so.w    1    ;0 to 15
  173. up_WordLen    so.b    1    ;0=5, 1=6, 2=7, 3=8
  174. up_StopBits    so.b    1    ;0=1, 1=2
  175. up_Parity    so.b    1    ;0=Odd, 1=Even, 2=Mark, 3=Space, 4=None
  176. up_Shake    so.b    1    ;0=RTS/CTS, 1=xON/xOFF
  177. up_Sizeof    soval
  178.  
  179. SerialPrefs_Struct    clrso
  180. sp_Unit01    so.b    up_Sizeof    ;For ACIA 0, Unit 1
  181. sp_Unit02    so.b    up_Sizeof    ;For ACIA 0, Unit 2
  182. sp_Unit11    so.b    up_Sizeof    ;For ACIA 1, Unit 1
  183. sp_Unit12    so.b    up_Sizeof    ;For ACIA 1, Unit 2
  184. serialprefs_Sizeof    soval
  185.  
  186. ;*** The Hardware ***
  187.  
  188. ACIA_Base    equ    $BF9000    ;Base address of all units
  189. ACIA1    equ    $800    ;Offset of 2nd chip
  190. UNIT2    equ    $400    ;Offset of 2nd unit
  191.  
  192. IER    equ    $0000    ;Interrupt Enable Register
  193. ISR    equ    $0000    ;Interrupt Status Register
  194. CTR    equ    $0100    ;Control Register
  195. FMR    equ    $0100    ;Format Register
  196. CSR    equ    $0100    ;Control Status Register
  197. CDR    equ    $0200    ;Compare Data Register
  198. ACR    equ    $0200    ;Auxilliary Control Register
  199. TDR    equ    $0300    ;Transmit Data Register
  200. RDR    equ    $0300    ;Receive Data Register
  201.  
  202. ;Interrupt Status Register
  203.  
  204.     BITDEF    ISR,SETCLR,7    ;Any bit set
  205.     BITDEF    ISR,TDRE,6    ;Transmit Data Register Empty
  206.     BITDEF    ISR,CTST,5    ;Transition on CTS* Line
  207.     BITDEF    ISR,DCDT,4    ;Transition on DCD* Line
  208.     BITDEF    ISR,DSRT,3    ;Transition on DSR* Line
  209.     BITDEF    ISR,PAR,2        ;Parity status
  210.     BITDEF    ISR,FEOB,1    ;Frame error, Overrun, Break
  211.     BITDEF    ISR,RDRF,0    ;Receive Data Register Full
  212.  
  213. ;Control Status Register
  214.  
  215.     BITDEF    CSR,FE,7        ;Framing Error
  216.     BITDEF    CSR,TUR,6        ;Transmitter Underrun
  217.     BITDEF    CSR,CTSL,5    ;CTS* Level
  218.     BITDEF    CSR,DCDL,4    ;DCD* Level
  219.     BITDEF    CSR,DSRL,3    ;DSR* Level
  220.     BITDEF    CSR,RBRK,2    ;Receive Break
  221.     BITDEF    CSR,DTRL,1    ;DTR* Level
  222.     BITDEF    CSR,RTSL,0    ;RTS* Level
  223.  
  224. ;*************************** Structures *************************
  225.  
  226. serprefs    clrso
  227. prefs_CTLCHAR    so.l    1    ;Control char's (order = xON,xOFF,rsvd,rsvd)
  228. prefs_RBUFLEN    so.l    1    ;Length in bytes of serial port's read buffer
  229. prefs_EXTFLAGS    so.l    1    ;Additional serial flags
  230. prefs_BAUD    so.l    1    ;Baud rate requested (true baud)
  231. prefs_BRKTIME    so.l    1    ;Duration of break signal in MICROseconds
  232. prefs_TERMARRAY    so.b    TERMARRAY_SIZE    ;Termination character array
  233. prefs_READLEN    so.b    1    ;Bits per read char (bit count)
  234. prefs_WRITELEN    so.b    1    ;Bits per write char (bit count)
  235. prefs_STOPBITS    so.b    1    ;Stopbits for read (count)
  236. prefs_SERFLAGS    so.b    1    ;See SERFLAGS bit definitions
  237. serprefs_sizeof    soval
  238.  
  239. MyDev    setso    LIB_SIZE
  240. md_Flags    so.b    1
  241. md_Pad1    so.b    1
  242. md_SysLib    so.l    1
  243. md_SegList    so.l    1
  244. md_Units    so.b    MD_NUMUNITS*4
  245. VectorBase    so.l    1
  246. MyPreviousAutoVec:    so.l    1
  247. ScoreBoard    so.w    1
  248. Chip1present    so.w    1
  249. Chip2present    so.w    1
  250. prefs_unit0    so.b    serprefs_sizeof    ;The reason why prefs are in this
  251. prefs_unit1    so.b    serprefs_sizeof    ;structure instead of the unit structure
  252. prefs_unit2    so.b    serprefs_sizeof    ;is that the pref settings should be saved
  253. prefs_unit3    so.b    serprefs_sizeof    ;across CloseDevice calls (which usually
  254. MyDev_Sizeof    soval            ;causes the unit to be dumped).
  255.  
  256. MyDevUnit    setso    UNIT_SIZE    ;Odd # longwords
  257. mdu_wport    so.b    MP_SIZE    ;MsgPort for write task
  258. MDU_FLAGS    so.b    1
  259. IERstate    so.b    1    ;Current state of IER used as a mask
  260. mdu_UnitNum    so.b    1
  261. frstate    so.b    1    ;This var mirrors a write-only register
  262. mdu_SysLib    so.l    1    ;Copy of location 4
  263. mdu_Device    so.l    1    ;Ptr to main device struct
  264. mdu_rstack    so.b    MYPROCSTACKSIZE    ;For read task
  265. mdu_wstack    so.b    MYPROCSTACKSIZE    ;For write task
  266. mdu_rtcb    so.b    TC_SIZE    ;Task Control Block (TCB) for read task
  267. mdu_wtcb    so.b    TC_SIZE    ;Task Control Block (TCB) for write task
  268. timerport    so.b    MP_SIZE
  269. timeriorequest    so.b    IOTV_SIZE
  270.  
  271. ;The -sig longwords must be contiguous!!!
  272. readsig    so.l    1    ;Read task signals
  273. readabortsig    so.l    1
  274.  
  275. tdresig    so.l    1    ;Write block finished
  276. writeabortsig    so.l    1
  277. xonsig    so.l    1    ;Comes from read task, and indicates xon received
  278.  
  279. HeadLong    so.w    1    ;Ptr to start of circular buffer (logical)
  280. Head    so.w    1
  281. TailLong    so.w    1    ;Ptr to end of circular buffer (logical)
  282. Tail    so.w    1
  283. StartBuf    so.l    1    ;Ptr to physical start of input buffer
  284. ReadRequestPtr    so.l    1
  285. WriteRequestPtr    so.l    1
  286. xstate    so.b    1    ;Zero if 'x-off' received, else $FF
  287. ISRcopy    so.b    1    ;Used for read error diagnosis
  288. CSRcopy    so.b    1    ;Used for read error diagnosis
  289. Exclusive    so.b    1    ;True if someone has exclusive access to this unit
  290. daciabase    so.l    1
  291. mdu_prefs    so.l    1    ;Ptr to prefs for this unit (in MyDev)
  292. WriteCount    so.l    1
  293. WriteBufferPtr    so.l    1
  294. MyDevUnit_Sizeof    soval
  295.  
  296. ;Note that we have a single unit structure used by both the read and write
  297. ;tasks (and the interrupt routine).
  298.  
  299. * UNIT_FLAG definitions:
  300.  
  301.     BITDEF    UNIT,BREAKSENT,2    ;break sent flag for Query
  302.     BITDEF    UNIT,READIMMEDIATE,3
  303.     BITDEF    UNIT,NEEDCHAR,4
  304.  
  305. * Bit definitions for MDU_FLAGS
  306.  
  307.     BITDEF    MDU,STOPPED,2    ;State bit for unit stopped
  308.     BITDEF    MDU,V,3    ;Buffer overflow flag - set in int routine if an overflow occurs
  309.     BITDEF    MDU,WaitingForChar,4
  310.     BITDEF    MDU,CharAvailable,5
  311.  
  312. * Bit definitions for ioflags
  313.  
  314.     BITDEF    ioflags,Ignore,4    ;Ignore this IO request
  315.  
  316. * Equates & bit defs for IERstate
  317.  
  318. READINT    equ    $87
  319. READINTMASK    equ    $7
  320.  
  321. WRITEINT    equ    $C0
  322. WRITEINTMASK    equ    $40
  323.  
  324. MYIDENT    macro
  325.     cstr    'newser.device V2.21 (September 26, 1992)',13,10
  326.     even
  327.     endm
  328.  
  329. ;The first executable location.  This should return an error in case someone
  330. ;tried to run us as a program (instead of loading us as a device).
  331.  
  332. FirstAddress:
  333.     moveq    #-1,d0
  334.     rts
  335.  
  336. ;A romtag structure.  After your driver is brought in from disk, the
  337. ;disk image will be scanned for this structure to discover magic constants
  338. ;about you (such as where to start running you from...).
  339.  
  340. initDDescrip:
  341.     dc.w    RTC_MATCHWORD    ;UWORD    RT_MATCHWORD (Magic cookie)
  342.     dc.l    initDDescrip    ;APTR    RT_MATCHTAG  (Back pointer)
  343.     dc.l    EndCode    ;APTR    RT_ENDSKIP   (To end of this hunk)
  344.     dc.b    RTF_AUTOINIT    ;UBYTE    RT_FLAGS     (magic-see "Init")
  345.     dc.b    VERSION    ;UBYTE    RT_VERSION
  346.     dc.b    NT_DEVICE    ;UBYTE    RT_TYPE      (must be correct)
  347.     dc.b    MYPRI    ;BYTE    RT_PRI
  348.     dc.l    myName    ;APTR    RT_NAME      (exec name)
  349.     dc.l    idString    ;APTR    RT_IDSTRING  (text string)
  350.     dc.l    Init    ;APTR    RT_INIT
  351.  
  352.     dc.b    'newser.device - Copyright (C) 1990, 1991, 1992 by Dan Babcock. ',0
  353.     even
  354.  
  355. ;nasty data area (makes this version non-ROMable)
  356.  
  357. OldVec:    dc.l    0
  358. Unit0:    dc.l    0
  359. Unit1:    dc.l    0
  360. _Unit2:    dc.l    0    ;_ used because of conflict with chip reg addr sym
  361. Unit3:    dc.l    0
  362.  
  363.  
  364. ;*********************** Tables (constant) **********************
  365.  
  366. ;Note!! Some of these values are depended on in the InitRoutine prefs
  367. ;code...i.e. they may not be changed arbitrarily!
  368.  
  369. defaultprefs:
  370.     dc.l    SER_DEFAULT_CTLCHAR ;prefs_CTLCHAR
  371.     dc.l    64*1024    ;prefs_RBUFLEN
  372.     dc.l    0    ;prefs_EXTFLAGS
  373.     dc.l    9600    ;prefs_BAUD
  374.     dc.l    250000    ;prefs_BRKTIME
  375.     dc.l    0    ;prefs_TERMARRAY
  376.     dc.l    0    ;prefs_TERMARRAY
  377.     dc.b    8    ;prefs_READLEN
  378.     dc.b    8    ;prefs_WRITELEN
  379.     dc.b    1    ;prefs_STOPBITS
  380. ;Note: RAD_BOOGIE must NOT be set here
  381.     dc.b    $88    ;prefs_SERFLAGS
  382.  
  383. ;Table of DACIA base addresses for the 4 units
  384.  
  385. basetable:
  386.     dc.l    ACIA_Base
  387.     dc.l    ACIA_Base+UNIT2
  388.     dc.l    ACIA_Base+ACIA1
  389.     dc.l    ACIA_Base+ACIA1+UNIT2
  390.  
  391. ;List of supported baud rates 
  392.  
  393. baudtable:
  394.     dc.w    50
  395.     dc.w    110
  396.     dc.w    135
  397.     dc.w    150
  398.     dc.w    300
  399.     dc.w    600
  400.     dc.w    1200
  401.     dc.w    1800
  402.     dc.w    2400
  403.     dc.w    3600
  404.     dc.w    4800
  405.     dc.w    7200
  406.     dc.w    9600
  407.     dc.w    19200
  408.     dc.w    38400
  409.     dc.w    31250    ;MIDI (external clock)
  410.  
  411. timername:
  412.     cstr    'timer.device'
  413.     even
  414.  
  415.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  416. subSysName:
  417.     cstr    'newser'    ;This name for debugging use
  418.     endc
  419.  
  420. myName:    dc.b    'newser.device',0    ;This is the name that the device will have
  421.     even
  422.  
  423. ;This is an identifier tag to help in supporting the device
  424. ;format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
  425.  
  426. idString:    MYIDENT
  427.  
  428. ;The romtag specified that we were "RTF_AUTOINIT".  This means that the
  429. ;RT_INIT structure member points to one of these tables below.  If the
  430. ;AUTOINIT bit was not set then RT_INIT would point to a routine to run.
  431.  
  432. Init:    dc.l    MyDev_Sizeof    ;data space size
  433.     dc.l    FuncTable    ;pointer to function initializers
  434.     dc.l    DataTable    ;pointer to data initializers
  435.     dc.l    InitRoutine    ;routine to run
  436.  
  437. FuncTable:
  438.     dc.w    -1    ;this indicates that the following are offsets,
  439.             ;rather than absolute addresses
  440.     dc.w    Open-FuncTable    ;standard system routines
  441.     dc.w    _Close-FuncTable
  442.     dc.w    Expunge-FuncTable
  443.     dc.w    Null-FuncTable    ;Reserved for future use!
  444.     dc.w    BeginIO-FuncTable    ;my device definitions
  445.     dc.w    AbortIO-FuncTable
  446.     dc.w    -1    ;function table end marker
  447.  
  448. ;The data table initializes static data structures. The format is
  449. ;specified in exec/InitStruct routine's manual pages.  The
  450. ;INITBYTE/INITWORD/INITLONG macros are in the file "exec/initializers.i".
  451. ;The first argument is the offset from the device base for this
  452. ;byte/word/long. The second argument is the value to put in that cell.
  453. ;The table is null terminated
  454.  
  455. DataTable:
  456.     INITBYTE    LN_TYPE,NT_DEVICE    ;Must be LN_TYPE!
  457.     INITLONG    LN_NAME,myName
  458.     INITBYTE    LIB_FLAGS,LIBF_SUMUSED+LIBF_CHANGED
  459.     INITWORD    LIB_VERSION,VERSION
  460.     INITWORD    LIB_REVISION,REVISION
  461.     INITLONG    LIB_IDSTRING,idString
  462.     dc.w    0    ;terminate list
  463.  
  464. ;This routine gets called after the device has been allocated.  The device
  465. ;pointer is in D0.  The AmigaDOS segment list is in a0.  If it returns the
  466. ;device pointer, then the device will be linked into the device list.  If it
  467. ;returns NULL, then the device will be unloaded.
  468. ;
  469. ;This call is single-threaded by exec; please read the description for
  470. ;"Open" below.
  471. ;
  472. ; Register Usage
  473. ; ==============
  474. ; a3 -- Points to temporary RAM
  475. ; a4 -- Expansion library base
  476. ; a5 -- device pointer
  477. ; a6 -- Exec base
  478.  
  479. InitRoutine:
  480.     PUTDEBUG    5,<'%s/Init: called'>
  481.     movem.l    d1-d7/a0-a6,-(sp)    ;Preserve ALL modified registers
  482.  
  483.     move.l    d0,a5
  484.     move.l    a6,(md_SysLib,a5)    ;Save a pointer to exec
  485.     move.l    a0,(md_SegList,a5)    ;Save pointer to our loaded code
  486.  
  487. ;Check for presence/absence of the 2 serial chips
  488.     moveq    #0,d0
  489.     moveq    #0,d1
  490.     move.l    #ACIA_Base,a4
  491.     move.b    #$83,(FMR,a4)
  492.     move.b    (CSR,a4),d2
  493.     and.b    #3,d2
  494.     cmp.b    #3,d2
  495.     bne.b    .Chip2
  496.     move.b    #$80,(FMR,a4)
  497.     move.b    (CSR,a4),d2
  498.     and.b    #3,d2
  499.     bne.b    .Chip2
  500.     moveq    #-1,d0
  501. .Chip2:
  502.     move.l    #ACIA_Base+ACIA1,a4
  503.     move.b    #$83,(FMR,a4)
  504.     move.b    (CSR,a4),d2
  505.     and.b    #3,d2
  506.     cmp.b    #3,d2
  507.     bne.b    .Done
  508.     move.b    #$80,(FMR,a4)
  509.     move.b    (CSR,a4),d2
  510.     and.b    #3,d2
  511.     bne.b    .Done
  512.     moveq    #-1,d1
  513.  
  514. .Done:
  515.     move.w    d0,(Chip1present,a5)
  516.     move.w    d1,(Chip2present,a5)
  517.  
  518. ;Take over level 6 autovector (nasty, but justified)
  519.     clr.l    (VectorBase,a5)
  520.     tst.w    (AttnFlags,a6)
  521.     beq.b    .skipvbr
  522.  
  523.     SYS    SuperState
  524.     movec    vbr,a2
  525.  
  526. ;Note that before 2.0, UserState was buggy. SetPatch fixes this for 1.3.
  527. ;As of newser V2.13 we assume that the function call will work.
  528.     SYS    UserState
  529.  
  530.     move.l    a2,(VectorBase,a5)
  531. .skipvbr:
  532.     move.l    (VectorBase,a5),a0
  533.     move.l    ($78,a0),(OldVec)
  534.     move.l    #Int0000,($78,a0)
  535.     move.l    #Int0000,(MyPreviousAutoVec,a5)
  536.     move.l    a5,a6
  537.     bsr    SetDefaultPrefs
  538.     move.l    4,a6
  539.  
  540. ;Try to find the prefs in memory
  541.     lea    (MagicPortName,pc),a1
  542.     SYS    FindPort
  543.     tst.l    d0
  544.     beq    .EndInit    ;use hard-coded defaults
  545.     move.l    d0,a0
  546.     lea    (MP_SIZE,a0),a3
  547.     move.l    a5,a6
  548.     lea    (prefs_unit0,a6),a2
  549.  
  550.     moveq    #3,d7    ;4 units
  551.     moveq    #0,d5
  552.  
  553. .OuterLoop:
  554.     move.l    d5,d6
  555.     lsl.w    #3,d6    ;Convert unit # to index
  556.     move.l    a3,a1
  557.     lea    (a1,d6.w),a1    ;UnitPrefs for this unit
  558. .PrefsLoop:
  559.     moveq    #0,d0
  560.     move.w    #512,d0
  561.     moveq    #0,d1
  562.     move.w    (up_BufSize,a1),d1 ;0-7
  563.     lsl.l    d1,d0
  564.     move.l    d0,(prefs_RBUFLEN,a2)
  565.  
  566.     lea    (baudtable,pc),a0
  567.     move.w    (up_BaudRate,a1),d0 ;0-15
  568.     add.w    d0,d0
  569.     moveq    #0,d1
  570.     move.w    (a0,d0.w),d1
  571.     move.l    d1,(prefs_BAUD,a2)
  572.  
  573.     moveq    #5,d1    ;5 bit word
  574.     move.b    (up_WordLen,a1),d0
  575.     beq.b    .WordLen    ;up_WordLen=0
  576.     addq.b    #1,d1    ;6 bit word
  577.     subq.b    #1,d0
  578.     beq.b    .WordLen    ;up_WordLen=1
  579.     addq.b    #1,d1    ;7 bit word
  580.     subq.b    #1,d0
  581.     beq.b    .WordLen    ;up_WordLen=2
  582.     addq.b    #1,d1    ;8 bit word
  583. .WordLen:
  584.     move.b    d1,(prefs_READLEN,a2)
  585.     move.b    d1,(prefs_WRITELEN,a2)
  586.  
  587.     move.b    (up_StopBits,a1),d0 ;0-1
  588.     addq.b    #1,d0
  589.     move.b    d0,(prefs_STOPBITS,a2)
  590.  
  591.     move.b    (up_Parity,a1),d0
  592.     cmp.b    #4,d0    ;none?
  593.     beq.b    .SkipParity
  594.     bset    #SERB_PARTY_ON,(prefs_SERFLAGS,a2)
  595.     cmp.b    #2,d0
  596.     bcc.b    .MarkSpace
  597.     bclr    #SERB_PARTY_ODD,(prefs_SERFLAGS,a2)    ;set to even
  598.     tst.b    d0
  599.     bne.b    .SkipParity
  600.     bset    #SERB_PARTY_ODD,(prefs_SERFLAGS,a2)    ;set to odd
  601.     bra.b    .SkipParity
  602. .MarkSpace:
  603.     bset    #SEXTB_MSPON,(3+prefs_EXTFLAGS,a2)
  604.     bclr    #SEXTB_MARK,(3+prefs_EXTFLAGS,a2)    ;set to space
  605.     cmp.b    #3,d0
  606.     beq.b    .SkipParity
  607.     bset    #SEXTB_MARK,(3+prefs_EXTFLAGS,a2)
  608.  
  609. .SkipParity:
  610.     move.b    (up_Shake,a1),d0
  611.     cmp.b    #2,d0
  612.     beq.b    .SkipShake
  613.     cmp.b    #1,d0
  614.     bne.b    .SkipXon
  615.     bclr    #SERB_XDISABLED,(prefs_SERFLAGS,a2)
  616.     bra.b    .SkipShake
  617. .SkipXon:
  618.     bset    #SERB_7WIRE,(prefs_SERFLAGS,a2)
  619. .SkipShake:
  620.     addq.l    #1,d5
  621.     add.w    #serprefs_sizeof,a2
  622.     dbra    d7,.OuterLoop
  623.  
  624. .EndInit:
  625.     move.l    a5,d0    ;no error (zero indicates error)
  626.             ;MUST return device ptr
  627.     PUTDEBUG    5,<'%s/Init: finished'>
  628.     movem.l    (sp)+,d1-d7/a0-a6
  629.     rts
  630.  
  631. MagicPortName:
  632.     dc.b    'newser_prefs',0
  633.     even
  634.  
  635. ;Enter with device ptr in a6.
  636.  
  637. SetDefaultPrefs:
  638.     movem.l    d0/d1/a0/a1,-(sp)
  639.     lea    (prefs_unit0,a6),a1
  640.     moveq    #MD_NUMUNITS-1,d1
  641. .L1:    move.w    #serprefs_sizeof-1,d0
  642.     lea    (defaultprefs,pc),a0
  643. .L2:    move.b    (a0)+,(a1)+
  644.     dbra    d0,.L2
  645.     dbra    d1,.L1
  646.     movem.l    (sp)+,d0/d1/a0/a1
  647.     rts
  648.  
  649. NewVector:
  650. ;Enter with device ptr in a6
  651. ;exit with d0=0 if OK, else error!
  652.  
  653. ;uses d0,a0,a1
  654.  
  655.     movem.l    a0/a1,-(sp)
  656.     move.l    (VectorBase,a6),a1
  657.     move.l    (MyPreviousAutoVec,a6),d0
  658.     cmp.l    ($78,a1),d0
  659.     bne.b    .Error
  660.  
  661.     moveq    #0,d0
  662.     move.b    (ScoreBoard,a6),d0
  663.     lsl.l    #2,d0
  664.     lea    (IntRoutines,pc),a0
  665.     move.l    (a0,d0.w),(MyPreviousAutoVec,a6)
  666.     move.l    (a0,d0.w),($78,a1)
  667.     moveq    #0,d0
  668. .End:
  669.     movem.l    (sp)+,a0/a1
  670.     rts
  671. .Error:
  672.     moveq    #1,d0
  673.     bra.b    .End
  674.  
  675. ;Here begins the system interface commands.  When the user calls OpenDevice/
  676. ;CloseDevice/RemDevice, this eventually gets translated into a call to the
  677. ;following routines (Open/Close/Expunge).  Exec has already put our device
  678. ;pointer in a6 for us.
  679. ;
  680. ;Open sets the IO_ERROR field on an error. If it was successful, we should
  681. ;also set up the IO_UNIT and LN_TYPE fields.  exec takes care of setting up
  682. ;IO_DEVICE.
  683. ;
  684. ;NOTE: We must also copy the current prefs for this unit into the user's
  685. ;extended iorequest fields.
  686. ;
  687. ; Register Usage
  688. ; ==============
  689. ; d0 -- unitnum
  690. ; d1 -- flags
  691. ; a1 -- iob
  692. ; a6 -- Device ptr
  693.  
  694. Open:
  695.     addq.w    #1,(LIB_OPENCNT,a6) ;Fake an opener for duration of call
  696.     PUTDEBUG    20,<'%s/Open: called'>
  697.     movem.l    d2/a2-a4,-(sp)
  698.     move.l    a1,a2    ;Save the iob
  699.     cmp.l    #MD_NUMUNITS,d0    ;See if the unit number is in range
  700.     bcc    Open_Range_Error    ;Unit number out of range (BHS)
  701.  
  702. ;Check to see if the corresponding chip is installed
  703.     lea    (Chip1present,a6),a4
  704.     tst.b    (a4,d0.w)
  705.     beq    Open_Range_Error
  706.  
  707.     move.l    d0,d2    ;Save unit number
  708.     lsl.l    #2,d0    ;See if the unit is already initialized
  709.     lea    (md_Units,a6,d0.l),a4
  710.     move.l    (a4),d0
  711.     bne.b    Open_UnitOK
  712.                 ;Try to conjure up a unit
  713.     bsr    InitUnit    ;scratch:a3 unitnum:d2 devpoint:a6
  714.     move.l    (a4),d0    ;See if it initialized OK
  715.     beq    Open_Error
  716.     move.l    d0,a3
  717.     btst    #SERB_SHARED,IO_SERFLAGS(a1)
  718.     seq    Exclusive(a3)
  719.     bra.b    Open_UnitOK1
  720.  
  721. Open_UnitOK:
  722.     move.l    d0,a3    ;Unit pointer in a3
  723.     tst.b    (Exclusive,a3)    ;Check for an exclusive access violation
  724.     bne    Open_Error
  725.     btst    #SERB_SHARED,IO_SERFLAGS(a1)
  726.     beq    Open_Error    ;doesn't want to share
  727. Open_UnitOK1:
  728.  
  729. ;If we get here then all is well. There's no way to fail anymore.
  730.  
  731. ;Set the "7WIRE" flag
  732.  
  733.     move.l    (mdu_prefs,a3),a4    ;Set the "7WIRE" flag
  734.     bclr    #SERB_7WIRE,(prefs_SERFLAGS,a4)
  735.     btst    #SERB_7WIRE,(IO_SERFLAGS,a2)
  736.     beq.b    2$
  737.     bset    #SERB_7WIRE,(prefs_SERFLAGS,a4)
  738.  
  739. 2$:    move.l    a2,a1    ;Copy the current internal prefs into the iorequest.
  740.     bsr    CopyPrefs
  741.     move.l    d0,(IO_UNIT,a2)
  742.     addq.w    #1,(LIB_OPENCNT,a6)  ;Mark us as having another opener
  743.     addq.w    #1,(UNIT_OPENCNT,a3) ;Internal bookkeeping
  744.     bclr    #LIBB_DELEXP,(md_Flags,a6) ;Prevent delayed expunges
  745.     clr.b    (IO_ERROR,a2)    ;no error
  746.     move.b    #NT_REPLYMSG,(LN_TYPE,a2) ;Mark IORequest as "complete"
  747. Open_End:
  748.     subq.w    #1,(LIB_OPENCNT,a6) ;End of expunge protection
  749.     movem.l    (sp)+,d2/a2-a4
  750.     PUTDEBUG 30,<'%s/Open: Finished!'>
  751.     rts
  752.  
  753. Open_Range_Error:
  754. Open_Error:
  755.     moveq    #IOERR_OPENFAIL,d0
  756.     move.b    d0,(IO_ERROR,a2)
  757.     move.l    d0,(IO_DEVICE,a2)    ;Trash IO_DEVICE on open failure
  758.     PUTDEBUG    2,<'%s/Open: failed'>
  759.     bra.b    Open_End
  760.  
  761. ;Copy prefs from our device struct to an IOrequest.  Enter with IORequest
  762. ;in a1 and unit pointer in a3.  All registers are preserved.
  763.  
  764. CopyPrefs:
  765.     movem.l    d0/a1/a4,-(sp)
  766.     move.l    (mdu_prefs,a3),a4
  767.     lea    (IO_CTLCHAR,a1),a1
  768.     move.w    #serprefs_sizeof-1,d0
  769. ..    move.b    (a4)+,(a1)+
  770.     dbra    d0,..
  771.     movem.l    (sp)+,d0/a1/a4
  772.     rts 
  773.  
  774. ;Copy prefs from an IOrequest to our device struct Enter with IORequest
  775. ;in a1 and unit pointer in a3.  All registers are preserved.
  776.  
  777. SetPrefs:
  778.     movem.l    d0/a1/a4,-(sp)
  779.     move.l    (mdu_prefs,a3),a4
  780.     lea    (IO_CTLCHAR,a1),a1
  781.     move.w    #serprefs_sizeof-1,d0
  782. ..    move.b    (a1)+,(a4)+
  783.     dbra    d0,..
  784.     movem.l    (sp)+,d0/a1/a4
  785.     rts 
  786.  
  787. ;There are two different things that might be returned from the Close
  788. ;routine.  If the device wishes to be unloaded, then Close must return
  789. ;the segment list (as given to Init).  Otherwise close MUST return NULL.
  790. ; ( device:a6, iob:a1 )
  791.  
  792. _Close:
  793.     movem.l    a2-a3,-(sp)
  794.     PUTDEBUG    20,<'%s/Close: called'>
  795.     move.l    a1,a2
  796.     move.l    (IO_UNIT,a2),a3
  797.     moveq    #-1,d0
  798.     move.l    d0,(IO_UNIT,a2)      ;We're closed...
  799.     move.l    d0,(IO_DEVICE,a2)    ;Customers not welcome at this IORequest!
  800.     subq.w    #1,(UNIT_OPENCNT,a3) ;See if the unit is still in use
  801.     bne.b    Close_Device
  802.     bsr    ExpungeUnit
  803.  
  804. Close_Device:
  805.     moveq    #0,d0
  806.     subq.w    #1,(LIB_OPENCNT,a6) ;Mark us as having one fewer openers
  807.     bne.b    Close_End     ;See if there is anyone left with us open
  808.     btst    #LIBB_DELEXP,(md_Flags,a6) ;See if we have a delayed expunge pending
  809.     beq.b    Close_End
  810.     bsr    Expunge    ;Do the expunge
  811. Close_End:
  812.     movem.l    (sp)+,a2-a3
  813.     PUTDEBUG    20,<'%s/Close: Finished!'>
  814.     rts        ;MUST return either zero or the SegList!
  815.  
  816. ;Expunge is called by the memory allocator when the system is low on
  817. ;memory.
  818. ;
  819. ;There are two different things that might be returned from the Expunge
  820. ;routine.  If the device is no longer open then Expunge may return the
  821. ;segment list (as given to Init).  Otherwise Expunge may set the
  822. ;delayed expunge flag and return NULL.
  823. ;
  824. ;One other important note: because Expunge is called from the memory
  825. ;allocator, it may NEVER Wait() or otherwise take long time to complete.
  826. ;
  827. ; A6          - library base (scratch)
  828. ; D0-D1/A0-A1 - scratch
  829.  
  830. Expunge:
  831.     PUTDEBUG    10,<'%s/Expunge: called'>
  832.     movem.l    d1/d2/a5/a6,-(sp)    ;Save ALL modified registers
  833.     move.l    a6,a5
  834.     move.l    (md_SysLib,a5),a6
  835.     tst.w    (LIB_OPENCNT,a5)    ;See if anyone has us open
  836.     beq.b    .DoIt
  837.     bset    #LIBB_DELEXP,(md_Flags,a5)    ;Set the delayed expunge flag
  838.     moveq    #0,d0
  839.     bra.b    Expunge_End
  840. .DoIt:
  841.  
  842. ;Important: If it's not possible to restore the old autovector, then don't
  843. ;expunge!!
  844. ;Restore old autovector if possible
  845.     move.l    (MyPreviousAutoVec,a5),a0
  846.     move.l    (VectorBase,a5),a1
  847.     cmp.l    ($78,a1),a0
  848.     beq.b    .ok
  849.     moveq    #0,d0
  850.     bra.b    Expunge_End
  851. .ok:
  852.     move.l    (OldVec,pc),($78,a1)
  853.  
  854.     move.l    (md_SegList,a5),d2 ;Store our seglist in d2
  855.     move.l    a5,a1     ;Unlink from device list
  856.     SYS    Remove     ;Remove first (before FreeMem)
  857.  
  858.     move.l    a5,a1     ;Devicebase
  859.     moveq    #0,d0
  860.     move.w    (LIB_NEGSIZE,a5),d0
  861.     sub.l    d0,a1    ;Calculate base of functions
  862.     add.w    (LIB_POSSIZE,a5),d0 ;Calculate size of functions + data area
  863.     SYS    FreeMem
  864.     move.l    d2,d0    ;Set up our return value
  865. Expunge_End:
  866.     movem.l    (sp)+,d1/d2/a5/a6
  867.     rts
  868.  
  869. Null:    moveq    #0,d0    ;The "Null" function MUST return zero.
  870.     rts
  871.  
  872. ;This is the main unit initialization routine. It allocates memory for
  873. ;the device structure, calls SetUpUnit, then calls InitTask.
  874.  
  875. ; ( d2:unit number, a3:scratch, a6:devptr )
  876.  
  877. InitUnit:
  878.     PUTDEBUG    30,<'%s/InitUnit: called'>
  879.     movem.l    d0/d1/a4/a2,-(sp)
  880.     move.l    d2,d1
  881.     mulu.w    #serprefs_sizeof,d1
  882.     lea    (prefs_unit0,a6),a4
  883.     add.l    d1,a4
  884.  
  885. ;Now A4 is a ptr to the prefs for this unit
  886.  
  887.     move.l    #MyDevUnit_Sizeof,d0 ;Allocate unit memory
  888.     move.l    #MEMF_PUBLIC!MEMF_CLEAR,d1
  889.     move.l    a6,-(sp)
  890.     move.l    (md_SysLib,a6),a6
  891.     SYS    AllocMem
  892.     move.l    (sp)+,a6
  893.     move.l    d0,a3
  894.     tst.l    d0
  895.     bne    continitunit1
  896.  
  897. ;Couldn't init the unit (out of memory).
  898.  
  899. ReturnVoid:
  900.     move.l    d2,d0    ;Unit number
  901.     lsl.l    #2,d0
  902.     clr.l    (md_Units,a6,d0.l) ;Set unit table
  903.     movem.l    (sp)+,d0/d1/a4/a2
  904.     rts
  905.  
  906. BadSetup:
  907.     bsr    KillTask
  908.     bra.b    ReturnVoid
  909.  
  910. continitunit1:
  911.     moveq    #0,d0    ;Don't need to re-zero it
  912.     move.l    a3,a2
  913.     lea    (mdu_Init,pc),a1
  914.     move.l    a6,-(sp)
  915.     move.l    (md_SysLib,a6),a6
  916.     SYS    InitStruct
  917.     move.l    (sp)+,a6
  918.  
  919.     move.l    a5,-(sp)    ;Look up DACIA base address
  920.     lea    (basetable,pc),a0
  921.     moveq    #0,d0
  922.     move.b    d2,d0
  923.     lsl.l    #2,d0
  924.     move.l    (0,a0,d0.w),a5 
  925.     move.l    a5,(daciabase,a3)
  926.  
  927.     move.b    #$7f,(IER,a5)     ;Disable DACIA interrupts
  928.  
  929.     bset    d2,(ScoreBoard,a6)
  930.     bsr    SetUpUnit
  931.     move.l    (sp)+,a5
  932.     tst.l    d0
  933.     bne.b    BadSetup
  934.  
  935.     bsr    InitTask    ;Set up the two tasks for this unit
  936.     tst.l    d0
  937.     beq.b    BadSetup
  938.  
  939. ;Done with InitUnit - fill in the proper md_Unit field in the device struct
  940. ;and return.
  941.     move.l    d2,d0    ;Unit number
  942.     lsl.l    #2,d0
  943.     move.l    a3,(md_Units,a6,d0.l) ;Set unit table
  944.     lea    (Unit0,pc),a2
  945.     move.l    a3,(a2,d0.l)
  946.     movem.l    (sp)+,d0/d1/a4/a2
  947.     PUTDEBUG    30,<'%s/InitUnit: finished! End of silence.'>
  948.     rts
  949.  
  950. ;This routine does the following:
  951. ;
  952. ;1. Allocate read buffer memory
  953. ;2. Initialize all the special MyDevUnit fields (but NOT the signals -
  954. ;   they must be allocated in the task's context)
  955. ;3. Call InitDACIA [Initialize/set-up DACIA registers (for this unit).]
  956. ;4. Install an interrupt server.
  957. ;
  958. ;Returns failure code in d0 - zero if OK, -1 if out of memory, 1 if
  959. ;unable to open timer.device, 2 if invalid parm
  960. ;
  961. ;SetUpUnit(d2:unit number, a3:unit, a6:devptr)
  962. ;AND...ptr to prefs in A4
  963. ;uses d1,a0,a1,a2,a6
  964.  
  965. SetUpUnit:
  966.     PUTDEBUG    30,<'%s/SetUpUnit: called'>
  967.     movem.l    d1/a0/a1/a2,-(sp)
  968.  
  969.     move.l    #65536,d0    ;buffer size
  970.     move.l    d0,(prefs_RBUFLEN,a4)
  971.  
  972.     move.l    #MEMF_PUBLIC,d1
  973.     EXEC    AllocMem
  974.     tst.l    d0
  975.     bne.b    continitunit
  976.     moveq    #-1,d0    ;Failed to allocate input buffer memory - exit.
  977.     movem.l    (sp)+,d1/a0/a1/a2
  978.     rts
  979.  
  980. ;Initialize all the special MyDevUnit fields (but NOT the signals -
  981. ;they must be allocated in the task's context)
  982.  
  983. continitunit:
  984.     move.l    d0,(StartBuf,a3)
  985.     clr.l    (HeadLong,a3)
  986.     clr.l    (TailLong,a3)
  987.  
  988.     move.l    a4,(mdu_prefs,a3)
  989.     move.l    4,(mdu_SysLib,a3) 
  990.     lea    (timerport+MP_MSGLIST,a3),a0
  991.     NEWLIST    a0         ;Init the unit's timer MsgPort's list
  992.     move.b    d2,(mdu_UnitNum,a3)    ;Initialize unit number
  993.     move.l    a6,(mdu_Device,a3)     ;Initialize device pointer
  994.     move.b    #$FF,(xstate,a3)
  995.     move.b    #$80,(frstate,a3)
  996.     bset    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  997.  
  998.     lea    (timername,pc),a0    ;Open the timer device.
  999.     moveq    #UNIT_MICROHZ,d0
  1000.     lea    (timeriorequest,a3),a1
  1001.     moveq    #0,d1 ;no special flags
  1002.     move.l    a6,-(sp)
  1003.     move.l    (md_SysLib,a6),a6
  1004.     SYS    OpenDevice
  1005.     move.l    (sp)+,a6
  1006.     tst.l    d0
  1007.     bne    OpenTimerFailed
  1008.  
  1009. ;Initialize/set-up DACIA registers (for this unit).
  1010. ;(according to the prefs pointed to by a4) 
  1011.  
  1012.     bsr    InitDACIA
  1013.     tst.l    d0
  1014.     bne    InitDACIAfailed 
  1015.  
  1016. ;Install an interrupt server.
  1017.  
  1018.     bsr    NewVector
  1019.     tst.l    d0
  1020.     bne.b    EndSetUpUnit
  1021.  
  1022.     moveq    #0,d0 ;situation under control
  1023.     movem.l    (sp)+,d1/a0/a1/a2
  1024.     PUTDEBUG    30,<'%s/SetUpUnit: Finished!'>
  1025.     rts
  1026.  
  1027. InitDACIAfailed:
  1028.     moveq    #2,d0
  1029.     bra.b    EndSetUpUnit
  1030.  
  1031. OpenTimerFailed:
  1032.     moveq    #1,d0
  1033. EndSetUpUnit:
  1034.     move.l    d0,-(sp)
  1035.     move.l    (prefs_RBUFLEN,a4),d0
  1036.     move.l    (StartBuf,a3),a1
  1037.     EXEC    FreeMem
  1038.     move.l    (sp)+,d0
  1039.     movem.l    (sp)+,d1/a0/a1/a2
  1040.     rts
  1041.  
  1042. ;****** end of SetUpUnit ******
  1043.  
  1044. ;Initialize/set-up DACIA registers (for this unit).
  1045. ;(according to the prefs pointed to by a4) 
  1046. ;d0.b will mirror CTR, d1.b will mirror FMR
  1047. ;Returns error code in d0 - zero if successful.
  1048. ;uses d1,d3,d5,a0
  1049.  
  1050. InitDACIA:
  1051.     PUTDEBUG    30,<'%s/InitDACIA: Called.'>
  1052.     movem.l    d1/d3/d5/a0,-(sp)
  1053.  
  1054. ;"During power-on initialization, all readable registers should be read to
  1055. ; assure that the status registers are initialized."
  1056.  
  1057.     move.b    (ISR,a5),d0
  1058.     move.b    (CSR,a5),d0
  1059.     move.b    (RDR,a5),d0
  1060.  
  1061.     move.b    (frstate,a3),d0    ;Set DTR* and RTS* low (assert)
  1062.     and.b    #$FC,d0    ;Clear bits zero and one
  1063.     move.b    d0,(frstate,a3)
  1064.     move.b    d0,(FMR,a5)
  1065.  
  1066.     moveq    #0,d0
  1067.     bset    #6,d0    ;Always access ACR, never CDR
  1068.     move.b    (frstate,a3),d1
  1069.   
  1070.     move.l    (prefs_BAUD,a4),d3 ;First, set proper baud rate.
  1071.  
  1072.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1073.     move.l    d3,-(sp)
  1074.     PUTDEBUG    150,<'%s/InitDACIA: %ldbps requested.'>
  1075.     addq.l    #4,sp
  1076.     endc
  1077.  
  1078.     swap    d3
  1079.     tst.w    d3
  1080.     bne    InvParm
  1081.     swap    d3
  1082.  
  1083. ;Test for (and allow) zero baud -- this makes Handshake happy
  1084. ;(Not a bug in Handshake.)  Old RKMs mentioned this behavior, but the
  1085. ;latest RKMs do not. Argh!
  1086.  
  1087.     tst.l    d3
  1088.     beq.b    SkipBAUD
  1089.  
  1090.     lea    (baudtable,pc),a0
  1091.     moveq    #15,d5 
  1092. baudloop:    cmp.w    (a0)+,d3
  1093.     dbeq    d5,baudloop
  1094.     bne    InvParm
  1095.     not.b    d5
  1096.     and.b    #$0F,d5
  1097.     or.b    d5,d0    
  1098.  
  1099.     ifne    INFO_LEVEL
  1100.     clr.l    -(sp)
  1101.     move.b    d0,(3,sp)
  1102.     PUTDEBUG    30,<'%s/InitDACIA: Baud rate = %lx'>
  1103.     addq.l    #4,sp
  1104.     endc
  1105.  
  1106. SkipBAUD:
  1107.     cmp.b    #1,(prefs_STOPBITS,a4) ;Next, set number of stop bits per character
  1108.     beq.b    onestop
  1109.     bset    #5,d0
  1110. onestop:
  1111.     move.b    d0,(CTR,a5)
  1112.  
  1113. ;set data bits per character
  1114.     move.b    (prefs_READLEN,a4),d3
  1115.     cmp.b    (prefs_WRITELEN,a4),d3
  1116.     bne    InvParm    ;We don't support different read & write char lengths
  1117.     subq.b    #5,d3
  1118.     bmi    InvParm
  1119.     cmp.b    #3,d3
  1120.     bhi    InvParm
  1121.     lsl.b    #5,d3
  1122.     and.b    #$80,d1    ;bug fix (clear before OR)
  1123.     or.b    d3,d1
  1124.  
  1125.     btst    #SEXTB_MSPON,(prefs_EXTFLAGS+3,a4) ;Set parity
  1126.     beq.b    EvenOdd
  1127.     bset    #2,d1
  1128.     btst    #SEXTB_MARK,(prefs_EXTFLAGS+3,a4)
  1129.     bne.b    UseMark
  1130.     or.b    #24,d1    ;Use space
  1131.     bra.b    NoParity
  1132.  
  1133. UseMark:    or.b    #16,d1
  1134.     bra.b    NoParity
  1135.  
  1136. EvenOdd:    btst    #SERB_PARTY_ON,(prefs_SERFLAGS,a4)
  1137.     beq.b    NoParity
  1138.     bset    #2,d1
  1139.  
  1140.     btst    #SERB_PARTY_ODD,(prefs_SERFLAGS,a4)
  1141.     bne.b    UseOdd
  1142.     or.b    #8,d1
  1143. UseOdd:
  1144. NoParity:
  1145.  
  1146.     ifne    INFO_LEVEL
  1147.     clr.l    -(sp)
  1148.     move.b    d1,(3,sp)
  1149.     PUTDEBUG    30,<'%s/InitDACIA: FMR = %lx'>
  1150.     addq.l    #4,sp
  1151.     endc
  1152.  
  1153.     move.b    d1,(frstate,a3)
  1154.     move.b    d1,(FMR,a5)
  1155.     moveq    #0,d0
  1156.     movem.l    (sp)+,d1/d3/d5/a0
  1157.     PUTDEBUG    30,<'%s/InitDACIA: Finished!'>
  1158.     rts
  1159.  
  1160. InvParm:    PUTDEBUG    30,<'%s/InitDACIA: Invalid Parm!'>
  1161.     moveq    #-1,d0
  1162.     movem.l    (sp)+,d1/d3/d5/a0
  1163.     rts
  1164.  
  1165. ;****** end of InitDACIA ******
  1166.  
  1167. ;(this is a subroutine for InitUnit)
  1168. ;This routine sets up the two tasks (one for reading, one for writing).
  1169. ;Returns zero in d0.l if an error occured else a ptr to the unit.
  1170. ;
  1171. ;uses d1-d4 and a0-a5
  1172.  
  1173. InitTask:
  1174.     PUTDEBUG    30,<'%s/InitTask: called.'>
  1175.     movem.l    d1-d4/a0-a5,-(sp)
  1176.     lea    (ReadTask_Begin,pc),a5 ;Set up the read task
  1177.     lea    (mdu_rstack,a3),a0
  1178.     lea    (mdu_rtcb,a3),a1
  1179.     move.l    a3,a2    ;Read message port
  1180.     bsr.b    InitTaskStruct
  1181.  
  1182.     lea    (WriteTask_Begin,pc),a5 ;Set up the write task
  1183.     lea    (mdu_wstack,a3),a0
  1184.     lea    (mdu_wtcb,a3),a1
  1185.     lea    (mdu_wport,a3),a2
  1186.     bsr.b    InitTaskStruct
  1187.  
  1188.     move.l    a3,d0    ;Mark us as ready to go
  1189.     PUTDEBUG    30,<'%s/InitTask: ok'>
  1190.  
  1191. ;Return zero in d0.l if an error occured, else a ptr to the unit
  1192.  
  1193.     movem.l    (sp)+,d1-d4/a0-a5
  1194.     rts
  1195.  
  1196. ;Start up the unit task.  We do a trick here --we set his message port to
  1197. ;PA_IGNORE until the new task has a change to set it up.  We cannot go to
  1198. ;sleep here: it would be very nasty if someone else tried to open the unit
  1199. ;(exec's OpenDevice has done a Forbid() for us --we depend on this to become
  1200. ;single threaded).
  1201. ;
  1202. ;Enter with:
  1203. ;a0 - ptr to low end of stack
  1204. ;a1 - ptr to tcb (task control block)
  1205. ;a3 - unit pointer
  1206. ;a5 - starting address of task
  1207. ;a2 - ptr to a (uninitialized) message port
  1208. ;
  1209. ;uses a0-a3 and d0,d1
  1210.  
  1211. InitTaskStruct:
  1212.     movem.l    d0/d1/a0-a3,-(sp)
  1213.     move.l    a0,(TC_SPLOWER,a1)    ;Initialize the stack information
  1214.     lea    (MYPROCSTACKSIZE,a0),a0 ;High end of stack
  1215.     move.l    a0,(TC_SPUPPER,a1)
  1216.     move.l    a3,-(a0)    ;Argument - unit ptr (send on stack)
  1217.     move.l    a0,(TC_SPREG,a1)
  1218.     move.l    a1,(MP_SIGTASK,a2)
  1219.  
  1220.     ifge    INFO_LEVEL-30
  1221.     move.l    a1,-(sp)
  1222.     move.l    a3,-(sp)
  1223.     PUTDEBUG    30,<'%s/InitUnit, unit= %lx, task=%lx'>
  1224.     addq.l    #8,sp
  1225.     endc
  1226.  
  1227.     lea    (MP_MSGLIST,a2),a0
  1228.     NEWLIST    a0    ;Init the unit's MsgPort's list
  1229.     move.l    a5,a2    ;Startup the task
  1230.     move.w    #-1,a3    ;generate address error
  1231.             ;if task ever "returns" (we RemTask() it
  1232.             ;to get rid of it...)
  1233.     moveq    #0,d0
  1234.     PUTDEBUG    30,<'%s/About to add task'>
  1235.     move.l    a6,-(sp)
  1236.     move.l    (md_SysLib,a6),a6
  1237.     SYS    AddTask
  1238.     move.l    (sp)+,a6
  1239.     movem.l    (sp)+,d0/d1/a0-a3
  1240.     rts
  1241.  
  1242. ;Get rid of the unit's tasks.  We know this is safe because the unit has an
  1243. ;open count of zero, so it is 'guaranteed' not in use.
  1244. ;
  1245. ;Kill the two tasks
  1246. ; ( a3:unitptr, a6:deviceptr )
  1247. ;
  1248. ;uses a0,a1 and d0-d2
  1249.  
  1250. KillTask:
  1251.     movem.l    a0/a1/d0-d2,-(sp)
  1252.     lea    (mdu_rtcb,a3),a1
  1253.     move.l    a6,-(sp)
  1254.     move.l    (md_SysLib,a6),a6
  1255.     SYS    RemTask
  1256.     move.l    (sp)+,a6
  1257.  
  1258.     lea    (mdu_wtcb,a3),a1
  1259.     move.l    a6,-(sp)
  1260.     move.l    (md_SysLib,a6),a6
  1261.     SYS    RemTask
  1262.     move.l    (sp)+,a6
  1263.  
  1264.     moveq    #0,d2
  1265.     move.b    (mdu_UnitNum,a3),d2 ;Save the unit number
  1266.     bsr    FreeUnit    ;Free the unit structure
  1267.     lsl.l    #2,d2
  1268.     clr.l    (md_Units,a6,d2.l)    ;Clear out the unit vector in the device
  1269.     movem.l    (sp)+,a0/a1/d0-d2
  1270.     rts
  1271.  
  1272. ; ( a3:unitptr, a6:deviceptr )
  1273. ;uses a0,a1,d0,d1
  1274.  
  1275. FreeUnit:
  1276.     movem.l    a0/a1/d0/d1,-(sp)
  1277.     move.l    a3,a1
  1278.     move.l    #MyDevUnit_Sizeof,d0
  1279.     move.l    a6,-(sp)
  1280.     move.l    (md_SysLib,a6),a6
  1281.     SYS    FreeMem
  1282.     move.l    (sp)+,a6
  1283.     movem.l    (sp)+,a0/a1/d0/d1
  1284.     rts
  1285.  
  1286. ; ( a3:unitptr, a6:deviceptr )
  1287. ;
  1288. ;uses a0,a1,a5,d0-d2
  1289.  
  1290. ExpungeUnit:
  1291.     movem.l    a0/a1/a5/d0-d2,-(sp)
  1292.     PUTDEBUG    10,<'%s/ExpungeUnit: called'>
  1293.  
  1294.     move.l    (daciabase,a3),a5
  1295.     move.b    #$7f,(IER,a5)    ;shut off all interrupts
  1296.     move.b    #$83,(FMR,a5)    ;Deassert DTR* and RTS*
  1297.  
  1298.     bsr    FreeResources
  1299.  
  1300.     lea    (mdu_rtcb,a3),a1
  1301.     move.l    a6,-(sp)
  1302.     move.l    (md_SysLib,a6),a6
  1303.     SYS    RemTask
  1304.     move.l    (sp)+,a6
  1305.  
  1306.     lea    (mdu_wtcb,a3),a1
  1307.     move.l    a6,-(sp)
  1308.     move.l    (md_SysLib,a6),a6
  1309.     SYS    RemTask
  1310.     move.l    (sp)+,a6
  1311.  
  1312.     moveq    #0,d2
  1313.     move.b    (mdu_UnitNum,a3),d2 ;Save the unit number
  1314.     bsr    FreeUnit    ;Free the unit structure.
  1315.  
  1316.     bclr    d2,(ScoreBoard,a6)
  1317.     bsr    NewVector
  1318.     lsl.l    #2,d2
  1319.     clr.l    (md_Units,a6,d2.l) ;Clear out the unit pointer in the device
  1320.  
  1321.     movem.l    (sp)+,a0/a1/a5/d0-d2
  1322.     rts
  1323.  
  1324. ;This routines frees up resources specific to this driver (the other
  1325. ;resources are taken care of by the skeleton).
  1326. ;Be careful with this routine, so as not to pull the rug out from
  1327. ;underneath the driver...
  1328. ;
  1329. ;Enter with unit ptr in a3 and device ptr in a6
  1330. ;
  1331. ;uses a0,a1,a4,d0,d1
  1332.  
  1333. FreeResources:
  1334.     PUTDEBUG    10,<'%s/FreeResources: called'>
  1335.     movem.l    a0/a1/a4/d0/d1,-(sp)
  1336.     move.l    (StartBuf,a3),a1    ;Free input buffer memory
  1337.     move.l    (mdu_prefs,a3),a4
  1338.     move.l    (prefs_RBUFLEN,a4),d0
  1339.     move.l    a6,-(sp)
  1340.     move.l    (md_SysLib,a6),a6
  1341.     SYS    FreeMem
  1342.     move.l    (sp)+,a6
  1343.  
  1344.     lea    (timeriorequest,a3),a1 ;Close timer device
  1345.     move.l    a6,-(sp)
  1346.     move.l    (md_SysLib,a6),a6
  1347.     SYS    CloseDevice
  1348.     move.l    (sp)+,a6
  1349.     movem.l    (sp)+,a0/a1/a4/d0/d1
  1350.     PUTDEBUG    10,<'%s/FreeResources: finished!'>
  1351.     rts
  1352.  
  1353. ;Here begins the device functions
  1354. ;
  1355. ;Cmdtable is used to look up the address of a routine that will
  1356. ;implement the device command.
  1357.  
  1358. cmdtable:
  1359.     dc.w    Invalid-cmdtable    ;0    CMD_INVALID
  1360.     dc.w    MyReset-cmdtable    ;1    CMD_RESET
  1361.     dc.w    Read-cmdtable    ;2    CMD_READ
  1362.     dc.w    Write-cmdtable    ;3    CMD_WRITE
  1363.     dc.w    Invalid-cmdtable    ;4    CMD_UPDATE (update has no meaning here)
  1364.     dc.w    MyClear-cmdtable    ;5    CMD_CLEAR
  1365.     dc.w    MyStop-cmdtable    ;6    CMD_STOP
  1366.     dc.w    Start-cmdtable    ;7    CMD_START
  1367.     dc.w    Flush-cmdtable    ;8    CMD_FLUSH
  1368.     dc.w    Query-cmdtable    ;9    SDCMD_QUERY
  1369.     dc.w    Break-cmdtable    ;10    SDCMD_BREAK
  1370.     dc.w    SetParams-cmdtable    ;11    SDCMD_SETPARAMS
  1371.     dc.w    Invalid-cmdtable    ;12    not used
  1372.     dc.w    Invalid-cmdtable    ;13    not used
  1373.     dc.w    Invalid-cmdtable    ;14    not used
  1374.     dc.w    Invalid-cmdtable    ;15    not used
  1375.     dc.w    SetControlLines-cmdtable    ;16 - ASDG extension
  1376.  
  1377. ;BeginIO starts all incoming io.  The IO is either queued up for the
  1378. ;unit task or processed immediately.
  1379. ;
  1380. ;BeginIO often is given the responsibility of making devices single
  1381. ;threaded... so two tasks sending commands at the same time don't cause
  1382. ;a problem.  Once this has been done, the command is dispatched.
  1383. ;
  1384. ;Some IO requests do not need single threading. These can be performed
  1385. ;immediatley.
  1386. ;The immediate commands are Invalid, Reset, Stop, Start, Flush, Clear,
  1387. ;Query, SetParams, and SetControlLines.
  1388. ;
  1389. ;IMPORTANT:
  1390. ; The exec WaitIO() function uses the IORequest node type (LN_TYPE)
  1391. ; as a flag.  If set to NT_MESSAGE, it assumes the request is
  1392. ; still pending and will wait.  If set to NT_REPLYMSG, it assumes the
  1393. ; request is finished.  It's the responsibility of the device driver
  1394. ; to set the node type to NT_MESSAGE before returning to the user.
  1395. ;
  1396. ;Notes: This routine looks at IO_COMMAND to determine which task
  1397. ;to use. Break and Write requests go to the write
  1398. ;task. Read requests (only) go to the read task. 
  1399. ;All other requests are performed immediately, i.e. within the caller's
  1400. ;context.
  1401. ;
  1402. ;This routine uses a3,a4,a5 (and a0/a1/d0/d1, but those do not need to be
  1403. ;preserved).
  1404. ; ( iob: a1, device:a6 )
  1405.  
  1406. ;************************** Start of BeginIO ***************************
  1407.  
  1408. BeginIO:
  1409.  
  1410.     movem.l    a3-a5,-(sp)
  1411.  
  1412.     ifge    INFO_LEVEL-1
  1413.     bchg.b    #1,($bfe001).l    ;Blink the power LED
  1414.     endc
  1415.  
  1416.     ifge    INFO_LEVEL-3
  1417.     clr.l    -(sp)
  1418.     move.w    (IO_COMMAND,a1),(2,sp) ;Get entire word
  1419.     PUTDEBUG    3,<'%s/BeginIO  --  %ld'>
  1420.     addq.l    #4,sp
  1421.     endc
  1422.  
  1423.     move.w    (IO_COMMAND,a1),d0
  1424.     cmp.w    #16,d0    ;command in range?
  1425.     bhi    .NoCmd    ;no, reject it.
  1426.  
  1427. ;Do some initial set-up work
  1428.     and.b    #$f,(IO_FLAGS,a1)    ;clear upper nibble
  1429.     move.b    #NT_MESSAGE,(LN_TYPE,a1) ;So WaitIO() is guaranteed to work
  1430.     move.l    (IO_UNIT,a1),a3    ;Bookkeeping -> what unit to play with
  1431.     move.l    (mdu_prefs,a3),a4
  1432.     move.l    (daciabase,a3),a5
  1433.     clr.b    (IO_ERROR,a1)    ;No error so far
  1434.  
  1435.     cmp.w    #CMD_READ,d0
  1436.     bne    .NotRead
  1437.  
  1438. ;If the task is busy reading, don't read in the caller's context!
  1439.     tst.l    (ReadRequestPtr,a3)
  1440.     bne.b    .ForgetIt
  1441.     lea    (MP_MSGLIST,a3),a0    ;Read port - anything there?
  1442.     move.l    (a0),a0
  1443.     tst.l    (a0)
  1444.     bne.b    .ForgetIt
  1445.  
  1446. ;Check whether there are enough characters in the buffer to do the read
  1447. ;immediately.
  1448.  
  1449.     btst    #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4)    ;Check for RAD_BOOGIE
  1450.     beq.b    .ForgetIt
  1451.     bsr    GetBytesInReadBuf
  1452.     cmp.l    (IO_LENGTH,a1),d0
  1453.     blo.b    .ForgetIt
  1454.     bset    #UNITB_READIMMEDIATE,(UNIT_FLAGS,a3)
  1455.     bne.b    .ForgetIt
  1456.     bsr    ReadImmediate
  1457.     bclr    #UNITB_READIMMEDIATE,(UNIT_FLAGS,a3)
  1458.     bra    .ReplyEnd
  1459. .ForgetIt:
  1460.  
  1461. ;Send message to read task
  1462.  
  1463.     move.l    a3,a0
  1464.     bra    .SendMessage
  1465.  
  1466. .NotRead:
  1467.     cmp.w    #CMD_WRITE,d0
  1468.     bne    .NotWrite
  1469.  
  1470.     moveq    #1,d0
  1471.     cmp.l    (IO_LENGTH,a1),d0
  1472.     bne    .QueueForWriteTask
  1473.  
  1474. ;If the write task is busy writing, don't write in the caller's context!
  1475.     tst.l    (WriteRequestPtr,a3)
  1476.     bne    .QueueForWriteTask
  1477.     lea    (mdu_wport+MP_MSGLIST,a3),a0    ;Write port - anything there?
  1478.     move.l    (a0),a0
  1479.     tst.l    (a0)
  1480.     bne    .QueueForWriteTask
  1481.  
  1482.     btst    #SERB_7WIRE,(prefs_SERFLAGS,a4)
  1483.     bne.b    .Handshake
  1484.     btst    #CSRB_CTSL,(CSR,a5)
  1485.     bne    .QueueForWriteTask
  1486. .Handshake:
  1487.     tst.b    (xstate,a3)
  1488.     beq    .QueueForWriteTask
  1489.  
  1490.     Disable
  1491.     bclr    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  1492.     beq.b    .NeedInt    ;Enable, then QueueForWriteTask
  1493.     move.l    (IO_DATA,a1),a0
  1494.     move.b    (a0),(TDR,a5)
  1495.     Enable
  1496.     bclr    #UNITB_BREAKSENT,(UNIT_FLAGS,a3)    ;for Query
  1497.     move.l    d0,(IO_ACTUAL,a1)
  1498.     bra.b    .ReplyEnd
  1499.  
  1500. .NotWrite:
  1501.     cmp.w    #SDCMD_BREAK,d0
  1502.     beq.b    .QueueForWriteTask    ;Handle just like a write request
  1503.  
  1504. ;execute immediately
  1505.     lea    (cmdtable,pc),a0
  1506.     add.w    d0,d0
  1507.     add.w    (a0,d0.w),a0
  1508.     jsr    (a0)
  1509.  
  1510. ;If the quick bit is set then we don't need to reply
  1511.  
  1512. .ReplyEnd:
  1513.     btst    #IOB_QUICK,(IO_FLAGS,a1)
  1514.     bne.b    .End
  1515.     push    a6
  1516.     move.l    4,a6
  1517.     SYS    ReplyMsg
  1518.     pop    a6
  1519. .End:    movem.l    (sp)+,a3-a5
  1520.     rts
  1521.  
  1522. .NeedInt:
  1523.     Enable
  1524.  
  1525. .QueueForWriteTask:
  1526. ;Send message to write task
  1527.  
  1528.     lea    (mdu_wport,a3),a0
  1529.  
  1530. .SendMessage:
  1531. ;Send the IO request as a "message" to either the read or write task
  1532. ;Enter with port address in A0 and IORequest in A1
  1533.  
  1534.     bclr    #IOB_QUICK,(IO_FLAGS,a1)    ;We did NOT complete this quickly
  1535.  
  1536.     ifge    INFO_LEVEL-250
  1537.     move.l    a1,-(sp)
  1538.     move.l    a0,-(sp)
  1539.     PUTDEBUG    250,<'%s/PutMsg: Port=%lx Message=%lx'>
  1540.     addq.l    #8,sp
  1541.     endc
  1542.  
  1543.     push    a6
  1544.     move.l    (md_SysLib,a6),a6
  1545.     SYS    PutMsg    ;Port=a0, Message=a1
  1546.     pop    a6
  1547.     bra    .End
  1548.  
  1549. .NoCmd:
  1550.     PUTDEBUG 200,<'%s/BeginIO_NoCmd!'>
  1551.     move.b    #IOERR_NOCMD,(IO_ERROR,a1)
  1552.     bra    .ReplyEnd
  1553.  
  1554. ;************************* End of BeginIO ****************************
  1555.  
  1556. ;Here begins the functions that implement the device commands
  1557. ;all functions are called with:
  1558. ;  a1 -- a pointer to the io request block
  1559. ;  a3 -- a pointer to the unit
  1560. ;  a4 -- a pointer to prefs
  1561. ;  a5 -- a pointer to the unit hardware
  1562. ;  a6 -- a pointer to the device
  1563. ;
  1564. ;Commands that conflict with 68000 instructions have a "My" prepended to them.
  1565.  
  1566. ;****************************** Read *****************************
  1567.  
  1568. Read:
  1569.     movem.l    d0-d6/a0/a2,-(sp)
  1570.  
  1571. ;Try to do a quick read
  1572.     btst    #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4)    ;Check for RAD_BOOGIE
  1573.     beq.b    .NoBoogie
  1574.  
  1575.     bsr    GetBytesInReadBuf
  1576.     cmp.l    (IO_LENGTH,a1),d0
  1577.     blo.b    .NotEnoughDataInBuf
  1578.     bsr    ReadImmediate
  1579.     bra    .FinalEndRead
  1580.  
  1581. .NoBoogie:
  1582. .NotEnoughDataInBuf:
  1583.  
  1584.     moveq    #0,d5    ;IO_ACTUAL
  1585.     move.l    (IO_LENGTH,a1),d6
  1586.     move.l    (IO_DATA,a1),a2
  1587.  
  1588.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1589.     move.l    d6,-(sp)
  1590.     PUTDEBUG    150,<'%s/Read entered -- %ld bytes requested.'>
  1591.     addq.l    #4,sp
  1592.     endc
  1593.  
  1594.     bra.b    .ReadEntry
  1595.  
  1596. .ReadLoop:
  1597.     PUTDEBUG    150,<'%s/Read: Waiting for signal from interrupt code.'>
  1598.     move.l    (readsig,a3),d0
  1599.     add.l    (readabortsig,a3),d0
  1600.     EXEC    Wait    ;Wait for one or more bytes to come in
  1601.     and.l    (readabortsig,a3),d0
  1602.     bne    .ReadAbort
  1603. .NoErrorAtAll:
  1604.     PUTDEBUG    150,<'%s/Read: One or more bytes came in.'>
  1605.  
  1606. .ReadEntry:
  1607.     bset    #MDUB_WaitingForChar,(MDU_FLAGS,a3)
  1608.     bsr    GetBytesInReadBuf
  1609.  
  1610.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1611.     move.l    d0,-(sp)
  1612.     PUTDEBUG    150,<'%s/Read: There are %ld bytes in the buffer.'>
  1613.     addq.l    #4,sp
  1614.     endc
  1615.  
  1616.     tst.l    d0
  1617.     beq    .ReadLoop
  1618.     cmp.l    d0,d6
  1619.     bls.b    .AllDone    ;Branch if d6 <= d0
  1620.     sub.l    d0,d6
  1621.     bsr    DumpReadBuf    ;Dump d0 bytes of the read buffer into the user's buffer
  1622.     tst.l    d0
  1623.     beq    .ReadLoop  
  1624.     bra.b    .EndRead    ;Go if TermArray caused early exit
  1625.  
  1626. ;The number of bytes in the read buffer equals or exceeds the number of
  1627. ;bytes the user wants.
  1628.  
  1629. .AllDone:
  1630.     PUTDEBUG    150,<'%s/Read: All done.'>
  1631.     move.l    d6,d0
  1632.     bsr    DumpReadBuf    ;Dump d0 bytes of the read buffer into the user's buffer
  1633. .EndRead:    PUTDEBUG    150,<'%s/Read: Finished!'>
  1634.  
  1635. ;    bclr    #MDUB_V,(MDU_FLAGS,a3)
  1636. ;    beq.b    NoOverflow
  1637. ;    move.b    #SerErr_BufOverflow,(IO_ERROR,a1)
  1638. ;NoOverflow:
  1639.  
  1640.     move.l    d5,(IO_ACTUAL,a1)
  1641. .FinalEndRead:
  1642.     movem.l    (sp)+,d0-d6/a0/a2
  1643.     rts        ;Done with read
  1644.  
  1645. ;Something exceptional happened.  An informative error code should be
  1646. ;returned.  first, check for error conditions...  Note that the serial.device
  1647. ;standard does not provide a way to inform the caller of simultaneous error
  1648. ;conditions.
  1649.  
  1650. .ReadAbort:
  1651.     PUTDEBUG    150,<'%s/readabort: Something exceptional happened.'>
  1652.     Disable
  1653.     move.b    (ISRcopy,a3),d2
  1654.     move.b    (CSRcopy,a3),d3
  1655.     clr.b    (ISRcopy,a3)
  1656.     clr.b    (CSRcopy,a3)
  1657.     Enable
  1658.     btst    #ISRB_PAR,d2
  1659.     beq.b    .notpar
  1660.  
  1661.     move.b    #SerErr_ParityErr,(IO_ERROR,a1)    ;parity error
  1662.     bra    .EndRead
  1663.  
  1664. .notpar:
  1665.     btst    #1,d2    ;Check for frame err, overrun, & break
  1666.     beq    .EndRead    ;We infer that an abort has been issued
  1667.  
  1668. ;This is a check for framing error....it might cause problems for
  1669. ;some auto-baud algorithms, so it's effectively disabled.
  1670.  
  1671.     btst    #CSRB_FE,d3    ;Probe further...
  1672.     beq.b    .noframe
  1673.     bra    .NoErrorAtAll
  1674. .noframe:
  1675.  
  1676.     btst    #CSRB_RBRK,d3
  1677.     beq.b    .NotBreak
  1678.     move.b    #SerErr_DetectedBreak,(IO_ERROR,a1)    ;Break
  1679.     bra    .EndRead 
  1680. .NotBreak:
  1681.  
  1682. ;Not framing error, not break, so must be a receive overrun condition.
  1683. ;Return with OVERRUN bit in IO_STATUS set.
  1684.  
  1685.     bset    #IOSTB_OVERRUN,IO_STATUS+1(a1)
  1686.     bra    .EndRead
  1687.  
  1688. ;****** Subroutines for the read routine ******
  1689.  
  1690. GetBytesInReadBuf:
  1691.  
  1692. ;Return with the number of bytes in the read buffer in d0
  1693.  
  1694.     move.l    d1,-(sp)
  1695.  
  1696.     movem.l    (HeadLong,a3),d0/d1    ;load HeadLong/TailLong
  1697.  
  1698.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1699.     move.l    d0,-(sp)
  1700.     PUTDEBUG    150,<'%s/GetBytesInReadBuf: HeadLong=%ld'>
  1701.     addq.l    #4,sp
  1702.     endc
  1703.  
  1704.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  1705.     move.l    d1,-(sp)
  1706.     PUTDEBUG    150,<'%s/GetBytesInReadBuf: TailLong=%ld'>
  1707.     addq.l    #4,sp
  1708.     endc
  1709.  
  1710.     sub.l    d0,d1
  1711.     bpl.b    .skipadd
  1712.     add.l    #65536,d1
  1713. .skipadd:
  1714.     move.l    d1,d0
  1715.  
  1716.     move.l    (sp)+,d1
  1717.     rts
  1718.  
  1719. ;Enter with number of bytes to read in d0
  1720. ;Enter with a pointer to a dump buffer in a2
  1721. ;the pointer in a2 is updated to reflect the current position
  1722. ;
  1723. ;This routine uses as scratch: d0,d5,d6,a2
  1724. ;and updates the following: d5,a2
  1725. ;Returns with D0=0 if all is OK, else a TermArray match was found.
  1726.  
  1727. ;This is a subroutine used only by Read
  1728.  
  1729. DumpReadBuf:
  1730.     movem.l    d1/d6/d7/a0/a6,-(sp)
  1731.     move.l    (HeadLong,a3),d1
  1732.     add.w    d0,(Head,a3)
  1733.     move.l    (StartBuf,a3),a0
  1734.  
  1735.     btst    #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4)
  1736.     bne.b    .Loop
  1737.  
  1738.     btst    #SERB_EOFMODE,(IO_SERFLAGS,a1)
  1739.     beq.b    .XLoop 
  1740.  
  1741. .EOFDump:
  1742.     moveq    #7,d7
  1743.     lea    (prefs_TERMARRAY,a4),a6
  1744.     move.b    (a0,d1.l),d6    ;index MUST be long (sign extended)!
  1745.     btst    #SERB_XDISABLED,(prefs_SERFLAGS,a4)
  1746.     bne.b    .Skip
  1747.     bsr    xcode
  1748. .Skip:    cmp.b    (a6)+,d6
  1749.     dbcc    d7,.Skip
  1750.     beq.b    .TermRead    
  1751.     move.b    d6,(a2)+
  1752.     addq.l    #1,d5
  1753.     addq.w    #1,d1
  1754.     subq.l    #1,d0
  1755.     bne.b    .EOFDump
  1756.     bra.b    .End
  1757.  
  1758. .Loop:
  1759.     move.b    (a0,d1.l),(a2)+    ;index MUST be long (sign extended)!
  1760.     addq.l    #1,d5    ;add to IO_ACTUAL
  1761.     addq.w    #1,d1    ;increment 16-bit head ptr
  1762.     subq.l    #1,d0
  1763.     bne.b    .Loop 
  1764.     bra.b    .End
  1765.  
  1766. .XLoop:
  1767.     move.b    (a0,d1.l),d6    ;index MUST be long (sign extended)!
  1768.     bsr.b    xcode
  1769.     move.b    d6,(a2)+
  1770.     addq.l    #1,d5    ;add to IO_ACTUAL
  1771.     addq.w    #1,d1    ;increment 16-bit head ptr
  1772.     subq.l    #1,d0
  1773.     bne.b    .XLoop 
  1774.     bra.b    .End
  1775.  
  1776. .TermRead:
  1777.     moveq    #-1,d0
  1778.     bra.b    .End1
  1779. .End:
  1780.     moveq    #0,d0
  1781. .End1:
  1782.     movem.l    (sp)+,d1/d6/d7/a0/a6
  1783.     rts
  1784.  
  1785. xcode:
  1786.  
  1787. ;Check for xon/xoff
  1788. ;Enter with current read character in d6.b
  1789.  
  1790.     ifne    INFO_LEVEL
  1791.     move.l    (prefs_CTLCHAR,a4),-(sp)
  1792.     PUTDEBUG    5,<'%s/XCODE: prefs_CTLCHAR = %lx'>
  1793.     addq.l    #4,sp
  1794.     endc
  1795.  
  1796.     ifne    INFO_LEVEL
  1797.     clr.l    -(sp)
  1798.     move.b    d6,(3,sp)
  1799.     PUTDEBUG    5,<'%s/XCODE: Current char = %lx'>
  1800.     addq.l    #4,sp
  1801.     endc
  1802.  
  1803.     cmp.b    (prefs_CTLCHAR,a4),d6    ;Xon check
  1804.     beq.b    .XON
  1805.     cmp.b    (prefs_CTLCHAR+1,a4),d6    ;Xoff check
  1806.     beq.b    .XOFF
  1807.     rts
  1808.  
  1809. .XON:    PUTDEBUG    5,<'%s/XCODE: XON!'>
  1810.     tst.b    (xstate,a3)
  1811.     bne.b    .End    ;If already on, don't signal!
  1812.     st    (xstate,a3)
  1813.     movem.l    d0/d1/a0/a1/a6,-(sp)
  1814.     move.l    (xonsig,a3),d0
  1815.     lea    (mdu_wtcb,a3),a1
  1816.     move.l    (mdu_SysLib,a3),a6
  1817.     SYS    Signal
  1818.     movem.l    (sp)+,d0/d1/a0/a1/a6
  1819. .End:    rts
  1820.  
  1821. .XOFF:    PUTDEBUG    5,<'%s/XCODE: XOFF!'>
  1822.     clr.b    (xstate,a3)
  1823.     rts
  1824.  
  1825. ReadImmediate:
  1826.  
  1827. ;Fast read routine
  1828. ;Requires boogie mode to be set and for there to be a sufficient number
  1829. ;of bytes in the buffer to completely satisfy the request.
  1830.  
  1831. ;Uses d0,d1,d2,d4,a0,a1,a2,a4,a6
  1832.  
  1833.     movem.l    d0-d2/d4/a0-a2/a4/a6,-(sp)
  1834.     push    a1
  1835.     move.l    (HeadLong,a3),d2
  1836.     move.l    (IO_LENGTH,a1),d4
  1837.     add.w    d4,(Head,a3)
  1838.     move.l    (IO_DATA,a1),a4
  1839.     move.l    (StartBuf,a3),a2
  1840.     move.l    (mdu_SysLib,a3),a6
  1841.  
  1842.     move.l    #65536,d0
  1843.     sub.l    d2,d0
  1844.     cmp.l    d0,d4
  1845.     bls.b    .UseIOLength
  1846.  
  1847. ;Need 2 copy operations
  1848.     sub.l    d0,d4
  1849.     move.l    a4,a1
  1850.     add.l    d0,a4
  1851.     lea    (a2,d2.l),a0
  1852.     SYS    CopyMem
  1853.     move.l    d4,d0
  1854.     move.l    a4,a1
  1855.     move.l    a2,a0
  1856.     SYS    CopyMem
  1857.     bra.b    .ReadQuickEnd
  1858.  
  1859. .UseIOLength:
  1860.     move.l    d4,d0
  1861.     move.l    a4,a1
  1862.     lea    (a2,d2.l),a0
  1863.     SYS    CopyMem
  1864. .ReadQuickEnd:
  1865.     pop    a1
  1866.     move.l    (IO_LENGTH,a1),(IO_ACTUAL,a1)
  1867.     movem.l    (sp)+,d0-d2/d4/a0-a2/a4/a6
  1868.     rts
  1869.  
  1870. ;*************************** Write ******************************
  1871.  
  1872. Write:
  1873.     comment |
  1874. Potential problem: If a TDRE interrupt happens, and just at that instant
  1875. (before the interrupt routine has time to kick into action) CTS is
  1876. deasserted, the interrupt routine will miss the TDRE condition and the
  1877. write routine will hang. This is unlikely, but possible. V2.10 adds
  1878. a time-out feature to avoid this if it ever happens in real life.
  1879. Testing the effectiveness of this solution is difficult, because I am
  1880. solving a problem that has, to my knowledge, never occured. (hehe)
  1881. |
  1882.  
  1883.     movem.l    d0-d5/a0-a2,-(sp)
  1884.     push    a1
  1885.     bclr    #UNITB_BREAKSENT,(UNIT_FLAGS,a3)    ;for Query
  1886.     btst    #SERB_7WIRE,(prefs_SERFLAGS,a4)
  1887.     bne.b    .Handshake
  1888.     btst    #CSRB_CTSL,(CSR,a5)
  1889.     bne    .NotConnected
  1890.  
  1891. .Handshake:
  1892.     move.l    (IO_DATA,a1),a2
  1893.     move.l    (IO_LENGTH,a1),d2
  1894.     beq    .End
  1895.     bpl.b    .CheckX
  1896.     move.l    a2,a0    ;handle zero-terminated writes
  1897. .L1:    tst.b    (a0)+
  1898.     bne.b    .L1
  1899.     sub.l    a2,a0
  1900.     move.l    a0,d2
  1901. .CheckX:
  1902.     tst.b    (xstate,a3)
  1903.     bne    .DoIt    ;go if no XOFF
  1904.  
  1905.     PUTDEBUG    5,<'%s/Transmit: Waiting for XON!'>
  1906.     move.l    (xonsig,a3),d0
  1907.     add.l    (writeabortsig,a3),d0
  1908.     EXEC    Wait    ;Wait for an x-on signal before sending
  1909.     and.l    (writeabortsig,a3),d0
  1910.     bne    .Abort
  1911.     PUTDEBUG    5,<'%s/Transmit: Received XON!'>
  1912.     bra    .CheckX
  1913.  
  1914. .DoIt:
  1915.     move.l    d2,d4
  1916.     Disable    ;quite neccessary!
  1917.     bclr    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  1918.     beq.b    .NeedInt
  1919.     move.b    (a2)+,(TDR,a5)    ;If set, we can load up the transmit reg immediately
  1920.     subq.l    #1,d4
  1921.     beq    .DoneWriting    ;does an Enable
  1922.  
  1923. .NeedInt:
  1924.     move.l    a2,(WriteBufferPtr,a3)
  1925.     move.l    d4,(WriteCount,a3)    ;GO!!!
  1926.     Enable
  1927.  
  1928.     lea    (timeriorequest,a3),a1
  1929.     move.l    (MN_REPLYPORT,a1),a0
  1930.     moveq    #0,d0
  1931.     move.b    (MP_SIGBIT,a0),d0
  1932.     moveq    #0,d3
  1933.     bset    d0,d3
  1934.  
  1935. .TopWaitBlock:
  1936.     moveq    #0,d5    ;clear danger flag
  1937. .WaitBlock:
  1938.     move.w    #TR_ADDREQUEST,(IO_COMMAND,a1)
  1939.     clr.l    (TV_SECS+IO_SIZE,a1)
  1940.     move.l    #100000,(TV_MICRO+IO_SIZE,a1)    ;100ms
  1941.     EXEC    SendIO
  1942.  
  1943.     move.l    d3,d0    ;timer signal
  1944.     add.l    (writeabortsig,a3),d0
  1945.     add.l    (tdresig,a3),d0
  1946.  
  1947. ;Wait for the block write to finish
  1948.     EXEC    Wait    ;Wait for write to finish
  1949.     move.l    d0,d1
  1950.     and.l    (tdresig,a3),d1
  1951.     beq.b    .NotTDRE
  1952.     EXEC    AbortIO    ;kill timer request
  1953.     EXEC    WaitIO
  1954.  
  1955. ;    PUTDEBUG    150,<'%s/Transmit: Write block finished.'>
  1956. .End:
  1957.     moveq    #0,d0    ;value
  1958.     move.l    d3,d1    ;mask
  1959.     EXEC    SetSignal    ;clear timer signal just in case
  1960.     pop    a1
  1961.     move.l    d2,(IO_ACTUAL,a1)
  1962.     movem.l    (sp)+,d0-d5/a0-a2
  1963.     rts
  1964. .NotTDRE:
  1965.     move.l    d0,d1
  1966.     and.l    (writeabortsig,a3),d1
  1967.     beq.b    .CheckOut
  1968.  
  1969. ;Abort signal
  1970.     EXEC    AbortIO    ;kill timer request
  1971.     EXEC    WaitIO
  1972.     bra    .Abort
  1973.  
  1974. .CheckOut:
  1975. ;If we end up here then a 100ms timeout has occured - so check a few
  1976. ;things...
  1977.     EXEC    WaitIO    ;remove the message from the replyport
  1978.     move.l    (WriteCount,a3),d0
  1979.     cmp.l    d4,d0    ;compare with previous WriteCount value
  1980.     beq.b    .Equal
  1981.     move.l    d0,d4
  1982.     bra    .TopWaitBlock
  1983. .Equal:
  1984.     btst    #CSRB_CTSL,(CSR,a5)
  1985.     bne    .TopWaitBlock    ;go if not asserted
  1986.     tst.l    d5
  1987.     bne.b    .Danger
  1988.     moveq    #1,d5    ;set danger flag
  1989.     bra    .WaitBlock
  1990. .Danger:
  1991.  
  1992. ;If we get here we know:
  1993. ;1. Nothing has been outputted (no TDRE) in the last 100-200+ ms, and
  1994. ;2. CTS is asserted (presumably at least 100ms -- we assume this)
  1995. ;So, we assume that we got unlucky and missed a TDRE, and force a byte out:
  1996.  
  1997.     Disable
  1998.     bclr    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  1999.     move.l    (WriteBufferPtr,a3),a0
  2000.     move.b    (a0)+,(TDR,a5)
  2001.     move.l    a0,(WriteBufferPtr,a3)
  2002.     subq.l    #1,(WriteCount,a3)
  2003.     beq.b    .DoneWriting
  2004.     Enable
  2005.     bra    .TopWaitBlock
  2006.  
  2007. .DoneWriting:
  2008.     Enable
  2009.     bra    .End
  2010. .NotConnected:
  2011.     move.b    #SerErr_LineErr,(IO_ERROR,a1)
  2012.     bra    .End
  2013. .Abort:
  2014.     sub.l    (WriteCount,a3),d2
  2015.     clr.l    (WriteCount,a3)
  2016.     bra    .End
  2017.  
  2018. ;******* end of write routine *******
  2019.  
  2020. Break:
  2021.     movem.l    d0-d2/a0/a1,-(sp)
  2022.     PUTDEBUG    5,<'%s/Break: called'>
  2023.     move.b    #2,(ACR,a5) ;start break
  2024.     bset    #UNITB_BREAKSENT,(UNIT_FLAGS,a3)
  2025.     lea    (timeriorequest,a3),a1
  2026.     move.w    #TR_ADDREQUEST,(IO_COMMAND,a1)
  2027.     clr.l    (TV_SECS+IO_SIZE,a1)
  2028.     move.l    (prefs_BRKTIME,a4),d0
  2029.     or.b    #$FF,d0    ;To avoid the V33/V34 timer bug
  2030.  
  2031.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  2032.     move.l    d0,-(sp)
  2033.     PUTDEBUG    5,<'%s/Break: TV_MICRO=%ld'>
  2034.     addq.l    #4,sp
  2035.     endc
  2036.  
  2037.     move.l    d0,(TV_MICRO+IO_SIZE,a1)
  2038.     move.l    (MN_REPLYPORT,a1),a0
  2039.     moveq    #0,d2
  2040.     move.b    (MP_SIGBIT,a0),d2
  2041.     EXEC    SendIO
  2042.     moveq    #0,d0
  2043.     bset    d2,d0
  2044.     add.l    (writeabortsig,a3),d0
  2045.  
  2046.     PUTDEBUG    5,<'%s/Break: Waiting...'>
  2047.  
  2048.     EXEC    Wait
  2049.     and.l    (writeabortsig,a3),d0
  2050.     beq.b    .BreakOK
  2051.  
  2052.     PUTDEBUG    5,<'%s/Break: Aborted!'>
  2053.  
  2054.     EXEC    AbortIO    ;The break was aborted. Clean up.
  2055. .BreakOK:
  2056.     EXEC    WaitIO 
  2057.     moveq    #0,d0    ;value
  2058.     moveq    #0,d1
  2059.     bset    d2,d1    ;mask
  2060.     EXEC    SetSignal    ;clear timer signal bit just in case
  2061.     move.b    #0,(ACR,a5) ;stop the break
  2062.  
  2063.     PUTDEBUG    5,<'%s/Break: Finished!'>
  2064.     movem.l    (sp)+,d0-d2/a0/a1
  2065.     rts
  2066.  
  2067. ;AbortIO() is a REQUEST to "hurry up" processing of an IORequest.
  2068. ;If the IORequest was already complete, nothing happens (if an IORequest
  2069. ;is quick or LN_TYPE=NT_REPLYMSG, the IORequest is complete).
  2070. ;The message must be replied with ReplyMsg(), as normal.
  2071. ;
  2072. ;Note that AbortIO is called directly, not via BeginIO.
  2073. ;
  2074. ;If sucessful, AbortIO returns IOERR_ABORTED in IO_ERROR and zero in D0
  2075.  
  2076. AbortIO:
  2077.     PUTDEBUG    5,<'%s/AbortIO: called'>
  2078.     Forbid
  2079.     movem.l    d1/a0/a1/a3,-(sp)
  2080.     move.l    (IO_UNIT,a1),a3
  2081.     move.b    #IOERR_ABORTED,(IO_ERROR,a1)    ;We always say we succeed(ed)
  2082.     cmp.b    #NT_REPLYMSG,(LN_TYPE,a1)    ;Already complete?
  2083.     beq.b    .End
  2084.     btst    #IOB_QUICK,(IO_FLAGS,a1)
  2085.     bne.b    .End
  2086.  
  2087. ;Check to see whether or not the IORequest is being processed 
  2088.  
  2089.     cmp.w    #CMD_READ,(IO_COMMAND,a1)
  2090.     bne.b    .NotRead
  2091.     cmp.l    (ReadRequestPtr,a3),a1
  2092.     bne.b    .NotActive
  2093.     move.l    (readabortsig,a3),d0
  2094.     lea    (mdu_rtcb,a3),a1
  2095. .Signal:    EXEC    Signal
  2096.     bra.b    .End
  2097. .NotRead:
  2098.     cmp.w    #CMD_WRITE,(IO_COMMAND,a1)
  2099.     bne.b    .NotWrite
  2100. .Write:    cmp.l    (WriteRequestPtr,a3),a1
  2101.     bne.b    .NotActive
  2102.     move.l    (writeabortsig,a3),d0
  2103.     lea    (mdu_wtcb,a3),a1
  2104.     bra.b    .Signal
  2105. .NotWrite:
  2106.     cmp.w    #SDCMD_BREAK,(IO_COMMAND,a1)
  2107.     beq.b    .Write
  2108.     bra.b    .End
  2109.  
  2110. .NotActive:
  2111. ;Set ignore bit in the IORequest
  2112.     bset    #ioflagsB_Ignore,(IO_FLAGS,a1)
  2113.  
  2114. .End:    Permit
  2115.     movem.l    (sp)+,d1/a0/a1/a3
  2116.     moveq    #0,d0    ;error code (always successful)
  2117.     PUTDEBUG    5,<'%s/AbortIO: Finished!'>
  2118.     rts
  2119.  
  2120. ;**************** End of AbortIO *****************
  2121.  
  2122. Invalid:
  2123.     move.b    #IOERR_NOCMD,(IO_ERROR,a1)
  2124.     rts
  2125.  
  2126. ;Clear invalidates all internal buffers.
  2127. ;
  2128. ; a1 -- a pointer to the io request block
  2129. ; a3 -- a pointer to the unit
  2130. ; a4 -- a pointer to prefs
  2131. ; a5 -- a pointer to the unit hardware
  2132. ; a6 -- a pointer to the device
  2133.  
  2134. MyClear:
  2135.     movem.l    d0/d1,-(sp)
  2136.     moveq    #0,d0
  2137.     moveq    #0,d1
  2138.     movem.l    d0/d1,(HeadLong,a3)
  2139.     movem.l    (sp)+,d0/d1
  2140.     rts
  2141.  
  2142. ; a1 -- a pointer to the io request block
  2143. ; a3 -- a pointer to the unit
  2144. ; a4 -- a pointer to prefs
  2145. ; a5 -- a pointer to the unit hardware
  2146. ; a6 -- a pointer to the device
  2147.  
  2148. MyReset:
  2149.     movem.l    d0/d7/a1,-(sp)
  2150.  
  2151.     PUTDEBUG    30,<'%s/MyReset: called'>
  2152.     Forbid
  2153.     move.b    (IERstate,a3),d7
  2154.     clr.b    (IERstate,a3)
  2155.     move.b    #$7f,(IER,a5)    ;Disable ACIA interrupts
  2156.     bsr    Flush    ;Flush pending requests
  2157.  
  2158. ;Abort current IO, if any IO is indeed occuring
  2159.  
  2160.     move.l    a1,-(sp)
  2161.  
  2162.     move.l    (WriteRequestPtr,a3),a1
  2163.     move.l    a1,d0
  2164.     beq.b    .WriteNotActive
  2165.     bsr    AbortIO
  2166.  
  2167. .WriteNotActive:
  2168.     move.l    (ReadRequestPtr,a3),a1
  2169.     move.l    a1,d0
  2170.     beq.b    .NothingActive
  2171.     bsr    AbortIO
  2172.  
  2173. .NothingActive:
  2174.     move.l    (sp)+,a1 
  2175.     bsr    SetDefaultPrefs
  2176.     bsr    CopyPrefs  
  2177.     bsr    FreeResources
  2178.     bsr    SetUpUnit
  2179.  
  2180.     tst.l    d0    ;Check for a possible error condition
  2181.     bmi.b    .OutOfMem
  2182.     subq.l    #1,d0
  2183.     beq.b    .TimerError
  2184.     subq.l    #1,d0
  2185.     beq.b    .ParamError
  2186.  
  2187.     move.b    d7,(IERstate,a3)    ;Enable DACIA interrupts again
  2188.     bset    #7,d7
  2189.     move.b    d7,(IER,a5)
  2190.     Permit
  2191.     clr.l    (IO_ACTUAL,a1)
  2192.     PUTDEBUG    30,<'%s/MyReset: Finished!'>
  2193. .ResetEnd:
  2194.     movem.l    (sp)+,d0/d7/a1
  2195.     rts
  2196.  
  2197. .ParamError:
  2198.     move.b    #SerErr_InvParam,(IO_ERROR,a1)
  2199.     bra.b    .MyResetFailed
  2200.  
  2201. .TimerError:
  2202.     move.b    #SerErr_TimerErr,(IO_ERROR,a1)
  2203.     bra.b    .MyResetFailed
  2204.  
  2205. .OutOfMem:
  2206.     move.b    #SerErr_BufErr,(IO_ERROR,a1)
  2207. .MyResetFailed:
  2208.     Permit
  2209.     clr.l    (IO_ACTUAL,a1)
  2210.     PUTDEBUG    30,<'%s/MyReset: Error!'>
  2211.     bra.b    .ResetEnd
  2212.  
  2213. ; a1 -- a pointer to the io request block
  2214. ; a3 -- a pointer to the unit
  2215. ; a4 -- a pointer to prefs
  2216. ; a5 -- a pointer to the unit hardware
  2217. ; a6 -- a pointer to the device
  2218. ;
  2219. ;Return number of chars in buffer in IO_ACTUAL
  2220. ;Fill in IO_STATUS
  2221.  
  2222. Query:
  2223.     movem.l    d0-d1,-(sp)
  2224. ;    PUTDEBUG    30,<'%s/Query: called.'>
  2225.  
  2226.     bsr    GetBytesInReadBuf
  2227.     move.l    d0,(IO_ACTUAL,a1)
  2228.  
  2229.     ifne    INFO_LEVEL  ;If any debugging enabled at all
  2230.     move.l    d0,-(sp)
  2231. ;    PUTDEBUG    30,<'%s/Query: %ld bytes in buf.'>
  2232.     move.l    (sp)+,d0
  2233.     endc
  2234.  
  2235.     moveq    #0,d0 ;d0 will mirror IO_STATUS
  2236.     move.b    (CSR,a5),d1
  2237.     btst    #0,d1
  2238.     beq.b    Q1
  2239.     bset    #6,d0
  2240. Q1:    btst    #1,d0
  2241.     beq.b    Q2
  2242.     bset    #7,d0
  2243. Q2:    btst    #3,d1
  2244.     beq.b    Q3
  2245.     bset    #3,d0
  2246. Q3:    btst    #4,d1
  2247.     beq.b    Q4
  2248.     bset    #5,d0    ;carrier detect
  2249. Q4:    btst    #5,d1
  2250.     beq.b    Q5
  2251.     bset    #4,d0
  2252. Q5:    btst    #UNITB_BREAKSENT,(UNIT_FLAGS,a3)
  2253.     beq.b    NB
  2254.     bset    #9,d0
  2255. NB:    btst    #2,d1
  2256.     beq.b    NRB
  2257.     bset    #10,d0
  2258. NRB:    tst.b    (xstate,a3)
  2259.     bne.b    xIsOn
  2260.     bset    #11,d0
  2261. xIsOn:    move.w    d0,(IO_STATUS,a1)
  2262.     movem.l    (sp)+,d0-d1
  2263.     rts
  2264.  
  2265. ; a1 -- a pointer to the io request block
  2266. ; a3 -- a pointer to the unit
  2267. ; a4 -- a pointer to prefs
  2268. ; a5 -- a pointer to the unit hardware
  2269. ; a6 -- a pointer to the device
  2270.  
  2271. SetParams:
  2272.     movem.l    d0/a0,-(sp)
  2273.     bclr    #SERB_XDISABLED,(prefs_SERFLAGS,a4)    ;enable
  2274.     btst    #SERB_XDISABLED,(IO_SERFLAGS,a1)
  2275.     beq.b    .NotDisabled
  2276.     bset    #SERB_XDISABLED,(prefs_SERFLAGS,a4)
  2277.     st    (xstate,a3)    ;set to X-ON state
  2278. .NotDisabled:
  2279.  
  2280. ;Now check to see whether the device is busy, i.e. any current or pending requests.
  2281.  
  2282.     Forbid
  2283.     tst.l    (ReadRequestPtr,a3)
  2284.     bne    .DevBusy
  2285.     tst.l    (WriteRequestPtr,a3)
  2286.     bne    .DevBusy
  2287.     lea    (MP_MSGLIST,a3),a0    ;Read port - anything there?
  2288.     move.l    (a0),a0
  2289.     tst.l    (a0)
  2290.     bne.b    .DevBusy
  2291.     lea    (mdu_wport+MP_MSGLIST,a3),a0    ;Write port - anything there?
  2292.     move.l    (a0),a0
  2293.     tst.l    (a0)
  2294.     bne.b    .DevBusy
  2295.  
  2296. ;Ok, the device is not busy. Set all params.
  2297.  
  2298.     bsr    SetPrefs    ;First copy the data
  2299.     move.l    #65536,(prefs_RBUFLEN,a4)
  2300.  
  2301. ;---> This section of code was supposed to increase compatibility, but
  2302. ;---> it actually decreases it!! The autodocs fail me again....
  2303. ;If boogie is set, it implies a few other things...(NOT!!!!)
  2304. ;    btst    #SERB_RAD_BOOGIE,(IO_SERFLAGS,a1) ;Check for RAD_BOOGIE
  2305. ;    beq.b    .SkipBoogie
  2306. ;    bclr    #SEXTB_MSPON,(prefs_EXTFLAGS+3,a4)
  2307. ;    bclr    #SERB_PARTY_ON,(prefs_SERFLAGS,a4)
  2308. ;    bset    #SERB_XDISABLED,(prefs_SERFLAGS,a4)
  2309. ;    move.b    #8,(prefs_READLEN,a4)
  2310. ;    move.b    #8,(prefs_WRITELEN,a4)
  2311. ;    bra.b    .SkipNext
  2312. ;.SkipBoogie:
  2313.  
  2314.  
  2315. ;The boogie flag is not set...but maybe it should be...
  2316. ;Note that this logic is depended on in the Read routine
  2317.     btst    #SERB_XDISABLED,(prefs_SERFLAGS,a4)
  2318.     beq.b    .nochance
  2319.     btst    #SERB_EOFMODE,(prefs_SERFLAGS,a4)
  2320.     bne.b    .nochance
  2321.     bset    #SERB_RAD_BOOGIE,(prefs_SERFLAGS,a4) ;Set RAD_BOOGIE !
  2322.  
  2323. .nochance:
  2324. .SkipNext:
  2325.     bsr    InitDACIA    ;Then set up the chip 
  2326.     tst.l    d0
  2327.     bne.b    .Invalid
  2328.  
  2329. .End:    Permit
  2330.     movem.l    (sp)+,d0/a0
  2331.     rts
  2332.  
  2333. .Invalid:    move.b    #SerErr_InvParam,(IO_ERROR,a1)
  2334.     bra.b    .End
  2335.  
  2336. .DevBusy:    move.b    #SerErr_DevBusy,(IO_ERROR,a1)
  2337.     bra.b    .End
  2338.  
  2339. SetControlLines:
  2340.  
  2341.     comment |
  2342.  
  2343. This routine is an extension specified by ASDG for their Dual Serial
  2344. Board. It allows application control of RTS and DTR. It works like this:
  2345.  
  2346. IO_COMMAND = 16
  2347.  
  2348. IO_OFFSET = mask
  2349. IO_LENGTH = value
  2350. Bit 0 = RTS
  2351. Bit 1 = DTR
  2352. |
  2353.  
  2354.     movem.l    d0-d2,-(sp)
  2355.     Forbid
  2356.     move.b    (frstate,a3),d0
  2357.     move.l    (IO_LENGTH,a1),d1    ;state
  2358.     move.l    (IO_OFFSET,a1),d2    ;mask
  2359.     and.b    d2,d1
  2360.     not.b    d2
  2361.     and.b    d2,d0    ;clear
  2362.     or.b    d1,d0    ;set
  2363.     move.b    d0,(frstate,a3)
  2364.     move.b    d0,(FMR,a5)
  2365.     Permit
  2366.     movem.l    (sp)+,d0-d2
  2367.     rts
  2368.  
  2369. ;The Stop command stop all future io requests from being processed until a
  2370. ;Start command is received. The Stop command is NOT stackable: e.g. no matter
  2371. ;how many stops have been issued, it only takes one Start to restart
  2372. ;processing.
  2373.  
  2374. MyStop:
  2375.     PUTDEBUG    30,<'%s/MyStop: called'>
  2376.     bset    #MDUB_STOPPED,(MDU_FLAGS,a3)
  2377.     rts
  2378.  
  2379. Start:
  2380.  
  2381. ;[A3=unit A6=device]
  2382.  
  2383.     movem.l    d0-d1/a0-a2,-(sp)
  2384.     PUTDEBUG    30,<'%s/Start: called'>
  2385.     move.l    a1,a2
  2386.  
  2387. ;Turn processing back on
  2388.     bclr    #MDUB_STOPPED,(MDU_FLAGS,a3)
  2389.  
  2390. ;Kick the tasks to start them moving
  2391.  
  2392.     move.b    (MP_SIGBIT,a3),d1    ;First the read task...
  2393.     moveq    #0,d0
  2394.     bset    d1,d0    ;Prepared signal mask
  2395.     move.l    (MP_SIGTASK,a3),a1    ;FIXED: marco-task to signal
  2396.     move.l    a6,-(sp)
  2397.     move.l    (md_SysLib,a6),a6
  2398.     SYS    Signal    ;FIXED: marco-a6 not a3
  2399.     move.l    (sp)+,a6
  2400.  
  2401.     move.l    a2,a1    ;Then the write task
  2402.     lea    (mdu_wport,a3),a0
  2403.     move.b    (MP_SIGBIT,a0),d1
  2404.     moveq    #0,d0
  2405.     bset    d1,d0    ;Prepared signal mask
  2406.     move.l    (MP_SIGTASK,a0),a1    ;FIXED: marco-task to signal
  2407.     move.l    a6,-(sp)
  2408.     move.l    (md_SysLib,a6),a6
  2409.     SYS    Signal    ;FIXED: marco-a6 not a3
  2410.     move.l    (sp)+,a6
  2411.     PUTDEBUG    30,<'%s/Start: Finished!'>
  2412.     movem.l    (sp)+,d0-d1/a0-a2
  2413.     rts
  2414.  
  2415. ;Flush pulls all I/O requests off the queue and sends them back.  We must be
  2416. ;careful not to destroy work in progress, and also that we do not let some io
  2417. ;requests slip by.
  2418.  
  2419. Flush:
  2420.     movem.l    d0-d1/a0/a1/a6,-(sp)
  2421.     PUTDEBUG    30,<'%s/Flush: called'>
  2422.     move.l    (md_SysLib,a6),a6
  2423.     SYS    Forbid
  2424. ReadFlush_Loop:
  2425.     move.l    a3,a0
  2426.     SYS    GetMsg    ;Steal messages from task's port
  2427.     tst.l    d0
  2428.     beq.b    WriteFlush_Loop
  2429.  
  2430.     move.l    d0,a1
  2431.     move.b    #IOERR_ABORTED,(IO_ERROR,a1)
  2432.     SYS    ReplyMsg
  2433.     bra.b    ReadFlush_Loop
  2434.  
  2435. WriteFlush_Loop:
  2436.     lea    (mdu_wport,a3),a0
  2437.     SYS    GetMsg    ;Steal messages from task's port
  2438.     tst.l    d0
  2439.     beq.b    Flush_End
  2440.  
  2441.     move.l    d0,a1
  2442.     move.b    #IOERR_ABORTED,(IO_ERROR,a1)
  2443.     SYS    ReplyMsg
  2444.     bra.b    WriteFlush_Loop
  2445.  
  2446. Flush_End:
  2447.     SYS    Permit
  2448.     PUTDEBUG    30,<'%s/Flush: Finished!'>
  2449.     movem.l    (sp)+,d0-d1/a0/a1/a6
  2450.     rts
  2451.  
  2452. ;Here begins the task related routines
  2453. ;
  2454. ; Register Usage
  2455. ; ==============
  2456. ; a2 -- device pointer
  2457. ; a3 -- unit pointer
  2458. ; a4 -- prefs pointer
  2459. ; a5 -- hardware pointer
  2460. ; a6 -- syslib pointer
  2461. ;----------------------------------------------------------------------
  2462. ;
  2463. ;Note: Signals must be allocated within this (the task's) context!
  2464. ;The task is responsible for enabling the right DACIA interrupts...AFTER
  2465. ;it has done its setup (like allocating signals).
  2466. ;
  2467. ;NOTE: We actually have two tasks, each with their own separate
  2468. ;      code (but shared data). First comes the read task...:
  2469.  
  2470. ReadTask_Begin:
  2471.     PUTDEBUG    35,<'%s/ReadTask_Begin'>
  2472.     move.l    4,a6
  2473.  
  2474. ;Grab the arguments passed down from our parent
  2475.  
  2476.     move.l    (4,sp),a3    ;Unit pointer
  2477.     move.l    (mdu_prefs,a3),a4
  2478.     move.l    (daciabase,a3),a5
  2479.  
  2480.     lea    (readsig,a3),a2
  2481.     moveq    #1,d6    ;Number of signals to allocate-1
  2482. ReadSigLoop:
  2483.     moveq    #-1,d0    ;-1 is any signal at all
  2484.     SYS    AllocSignal    ;Allocate signals for I/O interrupts
  2485.     moveq    #0,d7    ;Convert bit number signal mask
  2486.     bset    d0,d7
  2487.     move.l    d7,(a2)+    ;Save in unit structure
  2488.     dbra    d6,ReadSigLoop
  2489.  
  2490.     move.l    (mdu_Device,a3),a2    ;Point to device structure
  2491.  
  2492.     moveq    #-1,d0    ;-1 is any signal at all
  2493.     SYS    AllocSignal    ;Allocate a signal
  2494.     move.b    d0,(MP_SIGBIT,a3)
  2495.     move.b    #PA_SIGNAL,(MP_FLAGS,a3) ;Make message port "live"
  2496.  
  2497.     ifge    INFO_LEVEL-40
  2498.     move.l    ($114,a6),-(sp)
  2499.     move.l    (mdu_Device,a3),-(sp)
  2500.     move.l    a3,-(sp)
  2501.     move.l    d0,-(sp)
  2502.     PUTDEBUG    40,<'%s/ReadTask -- Signal=%ld, Unit=%lx Device=%lx Task=%lx'>
  2503.     add.l    #4*4,sp
  2504.     endc
  2505.  
  2506. ;Enable read-related ACIA interrupts
  2507.  
  2508.     or.b    #READINTMASK,(IERstate,a3)
  2509.     move.b    #READINT,(IER,a5)
  2510.     bra    ReadTask_NextMessage
  2511.  
  2512. ;OK, kids, we are done with initialization.  We now can start the main loop
  2513. ;of the driver.  It goes like this.  Because we had the port marked PA_IGNORE
  2514. ;for a while (in InitUnit) we jump to the getmsg code on entry.  (The first
  2515. ;message will probably be posted BEFORE our task gets a chance to run).
  2516. ;  wait for a message
  2517. ;  lock the device
  2518. ;  get a message.  If no message, unlock device and loop
  2519. ;  dispatch the message
  2520. ;  loop back to get a message
  2521.  
  2522. ;Main loop: wait for a new message
  2523.  
  2524. ReadTask_PermitMainLoop:
  2525.     Permit
  2526. ReadTask_MainLoop:
  2527.     PUTDEBUG    75,<'%s/ReadTask ++Sleep'>
  2528.     move.l    a3,a0
  2529.     SYS    WaitPort
  2530.     ifge    INFO_LEVEL-5
  2531.     bchg.b    #1,($bfe001).l  ;Blink the power LED
  2532.     endc
  2533.  
  2534.     PUTDEBUG    75,<'%s/ReadTask ++Wakeup'>
  2535.  
  2536.     btst    #MDUB_STOPPED,(MDU_FLAGS,a3)    ;See if we are stopped
  2537.     bne.b    ReadTask_MainLoop    ;Device is stopped, ignore messages
  2538.  
  2539. ReadTask_NextMessage:
  2540.     move.l    a3,a0
  2541.     Forbid
  2542.     SYS    GetMsg    ;Get the next request
  2543.     PUTDEBUG    1,<'%s/ReadTask GotMsg'>
  2544.     tst.l    d0
  2545.     beq    ReadTask_PermitMainLoop    ;no message?
  2546.  
  2547.     move.l    d0,a1    ;Do this request
  2548.     exg    a2,a6    ;Put device ptr in right place
  2549.  
  2550.     btst    #ioflagsB_Ignore,(IO_FLAGS,a1)
  2551.     bne.b    Readignorecmd
  2552.     move.l    a1,(ReadRequestPtr,a3)
  2553.     Permit
  2554.     bsr    Read    ;Do it!
  2555.     clr.l    (ReadRequestPtr,a3)
  2556.     EXEC    ReplyMsg
  2557.  
  2558. ;No longer active - abort has stopped sending signals. Now we can
  2559. ;(and should) clear the abort signal.
  2560.  
  2561.     moveq    #0,d0
  2562.     move.l    (readabortsig,a3),d1
  2563.     EXEC    SetSignal
  2564.     bra.b    Readconttl
  2565.  
  2566. Readignorecmd:
  2567.     Permit
  2568.     clr.l    (IO_ACTUAL,a1)
  2569.     EXEC    ReplyMsg
  2570. Readconttl:
  2571.     exg    a2,a6    ;Get ExecBase back in a6
  2572.     bra    ReadTask_NextMessage
  2573.  
  2574. ;**** End of read task code ****
  2575.  
  2576. ;**** Beginning of write task code ****
  2577.  
  2578. ; Register Usage
  2579. ; ==============
  2580. ; a2 -- device pointer
  2581. ; a3 -- unit pointer
  2582. ; a4 -- prefs pointer
  2583. ; a5 -- hardware pointer
  2584. ; a6 -- syslib pointer
  2585.  
  2586. WriteTask_Begin:
  2587.     PUTDEBUG    35,<'%s/WriteTask_Begin'>
  2588.     move.l    4,a6
  2589.  
  2590. ;Grab the arguments passed down from our parent
  2591.  
  2592.     move.l    (4,sp),a3    ;Unit pointer
  2593.     move.l    (mdu_prefs,a3),a4
  2594.     move.l    (daciabase,a3),a5
  2595.  
  2596.     lea    (tdresig,a3),a2
  2597.     moveq    #2,d6    ;Number of signals to allocate-1
  2598. WriteSigLoop:
  2599.     moveq    #-1,d0    ;-1 is any signal at all
  2600.     SYS    AllocSignal    ;Allocate signals for I/O interrupts
  2601.     moveq    #0,d7    ;Convert bit number signal mask
  2602.     bset    d0,d7
  2603.     move.l    d7,(a2)+    ;Save in unit structure
  2604.     dbra    d6,WriteSigLoop
  2605.  
  2606. ;Allocate a signal for the timer message port
  2607.  
  2608.     moveq    #-1,d0    ;-1 is any signal at all
  2609.     SYS    AllocSignal
  2610.     lea    (timerport,a3),a2
  2611.     move.b    d0,(MP_SIGBIT,a2)
  2612.     move.l    a2,(timeriorequest+MN_REPLYPORT,a3)
  2613.     sub.l    a1,a1
  2614.     SYS    FindTask
  2615.     move.l    d0,(MP_SIGTASK,a2)    
  2616.     move.b    #PA_SIGNAL,(MP_FLAGS,a2) ;Make message port "live"
  2617.  
  2618.     move.l    (mdu_Device,a3),a2    ;Point to device structure
  2619.  
  2620. ;Allocate a signal for the cmd message port
  2621.  
  2622.     moveq    #-1,d0    ;-1 is any signal at all
  2623.     SYS    AllocSignal
  2624.     move.b    d0,(mdu_wport+MP_SIGBIT,a3)
  2625.     move.b    #PA_SIGNAL,(mdu_wport+MP_FLAGS,a3) ;Make message port "live"
  2626.  
  2627.     ifge    INFO_LEVEL-40
  2628.     move.l    (ThisTask,a6),-(sp)
  2629.     move.l    a5,-(sp)
  2630.     move.l    a3,-(sp)
  2631.     move.l    d0,-(sp)
  2632.     PUTDEBUG    40,<'%s/WriteTask -- Signal=%ld, Unit=%lx Device=%lx Task=%lx'>
  2633.     add.l    #4*4,sp
  2634.     endc
  2635.  
  2636. ;Enable write-related ACIA interrupts
  2637.  
  2638.     or.b    #WRITEINTMASK,(IERstate,a3)
  2639.     move.b    #WRITEINT,(IER,a5)
  2640.     bra    WriteTask_NextMessage
  2641.  
  2642. ;Main loop: wait for a new message
  2643.  
  2644. WriteTask_PermitMainLoop:
  2645.     Permit
  2646. WriteTask_MainLoop:
  2647.     PUTDEBUG    75,<'%s/WriteTask ++Sleep'>
  2648.  
  2649.     lea    (mdu_wport,a3),a0
  2650.     SYS    WaitPort
  2651.  
  2652.     ifge    INFO_LEVEL-5
  2653.     bchg.b    #1,($bfe001).l  ;Blink the power LED
  2654.     endc
  2655.     PUTDEBUG    75,<'%s/WriteTask ++Wakeup'>
  2656.  
  2657.     btst    #MDUB_STOPPED,(MDU_FLAGS,a3)    ;See if we are stopped
  2658.     bne    ReadTask_MainLoop    ;Device is stopped, ignore messages
  2659.  
  2660. WriteTask_NextMessage:
  2661.     lea    (mdu_wport,a3),a0
  2662.     Forbid
  2663.     SYS    GetMsg    ;Get the next request
  2664.     PUTDEBUG    1,<'%s/WriteTask GotMsg'>
  2665.     tst.l    d0
  2666.     beq    WriteTask_PermitMainLoop    ;No message?
  2667.  
  2668.     move.l    d0,a1    ;Do this request
  2669.     exg    a2,a6    ;Put device ptr in right place
  2670.  
  2671.     btst    #ioflagsB_Ignore,(IO_FLAGS,a1)
  2672.     bne.b    Writeignorecmd
  2673.     move.l    a1,(WriteRequestPtr,a3)
  2674.     Permit
  2675.     cmp.w    #CMD_WRITE,(IO_COMMAND,a1)
  2676.     bne.b    .NotWrite
  2677.     bsr    Write
  2678.     bra.b    .Continue
  2679. .NotWrite:
  2680.     bsr    Break
  2681. .Continue:
  2682.     clr.l    (WriteRequestPtr,a3)
  2683.     EXEC    ReplyMsg
  2684.  
  2685. ;No longer active - abort has stopped sending signals. Now we can
  2686. ;(and should) clear the abort signal.
  2687.  
  2688.     moveq    #0,d0
  2689.     move.l    (writeabortsig,a3),d1
  2690.     EXEC    SetSignal
  2691.     bra.b    Writeconttl
  2692.  
  2693. Writeignorecmd:
  2694.     Permit
  2695.     clr.l    (IO_ACTUAL,a1)
  2696.     EXEC    ReplyMsg
  2697. Writeconttl:
  2698.     exg    a2,a6    ; get syslib back in a6
  2699.     bra    WriteTask_NextMessage
  2700.  
  2701. ;********** end of write task code ***********
  2702.  
  2703. ;Initialize the device
  2704.  
  2705. mdu_Init:
  2706. ;Initialize read task message port/tcb
  2707.     INITBYTE    MP_FLAGS,PA_IGNORE    ;Unit starts with read message port
  2708.     INITBYTE    LN_TYPE,NT_MSGPORT
  2709.     INITLONG    LN_NAME,myName
  2710.     INITLONG    mdu_rtcb+LN_NAME,myName
  2711.     INITBYTE    mdu_rtcb+LN_TYPE,NT_TASK
  2712.     INITBYTE    mdu_rtcb+LN_PRI,127
  2713.  
  2714. ;Initialize write task message port/tcb
  2715.  
  2716.     INITBYTE    mdu_wport+MP_FLAGS,PA_IGNORE    ;Write message port
  2717.     INITBYTE    mdu_wport+LN_TYPE,NT_MSGPORT
  2718.     INITLONG    mdu_wport+LN_NAME,myName
  2719.     INITLONG    mdu_wtcb+LN_NAME,myName
  2720.     INITBYTE    mdu_wtcb+LN_TYPE,NT_TASK
  2721.     INITBYTE    mdu_wtcb+LN_PRI,126
  2722.  
  2723. ;Initialize timer message port
  2724.  
  2725.     INITBYTE    timerport+MP_FLAGS,PA_IGNORE    ;Timer message port
  2726.     INITBYTE    timerport+LN_TYPE,NT_MSGPORT
  2727.     INITLONG    timerport+LN_NAME,myName
  2728.  
  2729.     dc.w    0
  2730.  
  2731. ;******************** Interrupt code *********************************
  2732.  
  2733. ;Notes:
  2734.  
  2735. ;In this version of the driver we use a single interrupt routine for all
  2736. ;units, and that routine bypasses the usual Exec conventions. Normally
  2737. ;this would be bad, but the need for speed certainly warrents it in this
  2738. ;case.
  2739.  
  2740. ;This is the interrupt routine. It serves three purposes:
  2741. ;1. Read in a byte if available, store it, and signal the read task
  2742. ;2. Check for TDRE-empty condition and signal write task
  2743. ;3. Check for an exceptional condition and signal read task
  2744.  
  2745. ;uses d0,d7,a0,a3,a5
  2746.  
  2747. DoInt    macro
  2748.     movem.l    d0/d7/a0/a3/a5,-(sp)
  2749.  
  2750.     ifge    \1-1
  2751.     move.l    (Unit3,pc),a3
  2752.     move.l    (daciabase,a3),a5
  2753.     move.b    (ISR,a5),d7
  2754.     and.b    (IERstate,a3),d7    ;Quick check (note that this masking is very
  2755.                 ;important)
  2756.     bne    FastInt    ;Service it
  2757.     endc
  2758.  
  2759.     ifge    \2-1
  2760.     move.l    (_Unit2,pc),a3
  2761.     move.l    (daciabase,a3),a5
  2762.     move.b    (ISR,a5),d7
  2763.     and.b    (IERstate,a3),d7    ;Quick check (note that this masking is very
  2764.                 ;important)
  2765.     bne    FastInt    ;Service it
  2766.     endc
  2767.  
  2768.     ifge    \3-1
  2769.     move.l    (Unit1,pc),a3
  2770.     move.l    (daciabase,a3),a5
  2771.     move.b    (ISR,a5),d7
  2772.     and.b    (IERstate,a3),d7    ;Quick check (note that this masking is very
  2773.                 ;important)
  2774.     bne    FastInt    ;Service it
  2775.     endc
  2776.  
  2777.     ifge    \4-1
  2778.     move.l    (Unit0,pc),a3
  2779.     move.l    (daciabase,a3),a5
  2780.     move.b    (ISR,a5),d7
  2781.     and.b    (IERstate,a3),d7    ;Quick check (note that this masking is very
  2782.                 ;important)
  2783.     bne    FastInt    ;Service it
  2784.     endc
  2785.  
  2786.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2787.     move.l    (OldVec,pc),-(sp)
  2788.     rts
  2789.  
  2790.     endm
  2791.  
  2792. IntRoutines:
  2793.     dc.l    Int0000    ;dummy entry for 0
  2794.     dc.l    Int0001
  2795.     dc.l    Int0010
  2796.     dc.l    Int0011
  2797.     dc.l    Int0100
  2798.     dc.l    Int0101
  2799.     dc.l    Int0110
  2800.     dc.l    Int0111
  2801.     dc.l    Int1000
  2802.     dc.l    Int1001
  2803.     dc.l    Int1010
  2804.     dc.l    Int1011
  2805.     dc.l    Int1100
  2806.     dc.l    Int1101
  2807.     dc.l    Int1110
  2808.     dc.l    Int1111
  2809.  
  2810. ;************* Start of fast interrupt routine **************
  2811.  
  2812. FastInt:
  2813.  
  2814. ;****** NOTE/WARNING:  Reading the ISR will cause the interrupt line
  2815. ;****** to be deasserted, although the bits in the ISR (except for read
  2816. ;****** error bits) will stay set ---- therefore simultaneous
  2817. ;****** conditions MUST!!!! be checked for!!!!!! There is no
  2818. ;****** second chance!
  2819.  
  2820.  
  2821. ;Read error condition?
  2822. ;(Note: Reading the RDR clears the error flags.)
  2823.     move.b    d7,d0
  2824.     and.b    #6,d0
  2825.     bne.b    ReadErr    ;read errors?
  2826.  
  2827.     btst    #ISRB_RDRF,d7    ;Test Receive Data Buffer Full
  2828.     beq.b    DoTDRE
  2829.  
  2830. DoRDRF:
  2831. ;    PUTDEBUG    75,<'%s/Int: Read.'>
  2832.  
  2833. ;Store the byte in the circular buffer.  Note that this code *can't* be
  2834. ;interrupted, so we're safe (that's because CIA B, which we're plugging into,
  2835. ;is connected to INT6*).
  2836.  
  2837.     move.l    (TailLong,a3),d0    ;Read and store
  2838.     move.l    (StartBuf,a3),a0
  2839.     move.b    (RDR,a5),(a0,d0.l)
  2840.     addq.w    #1,(Tail,a3)
  2841.  
  2842. ;Currently waiting for a character?
  2843.     btst    #MDUB_WaitingForChar,(MDU_FLAGS,a3)
  2844.     bne.b    SignalRead    ;yes, signal read task
  2845.     bset    #MDUB_CharAvailable,(MDU_FLAGS,a3)
  2846.  
  2847.     btst    #ISRB_TDRE,d7
  2848.     bne.b    DoTDRE
  2849.  
  2850. ;Return from int routine
  2851.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2852.     move.w    #$2000,(_custom+intreq)
  2853.     rte
  2854.  
  2855. DoTDRE:
  2856. ;Continue with int routine...
  2857.  
  2858. ;We can deduce that the interrupt was caused by TDRE
  2859. ;Therefore we have something to write...
  2860.  
  2861.     tst.l    (WriteCount,a3)
  2862.     beq.b    SetNeedChar
  2863.  
  2864.     bclr    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  2865.     move.l    (WriteBufferPtr,a3),a0
  2866.     move.b    (a0)+,(TDR,a5)
  2867.     move.l    a0,(WriteBufferPtr,a3)
  2868.     subq.l    #1,(WriteCount,a3)
  2869.     beq.b    DoneWriting
  2870.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2871.     move.w    #$2000,(_custom+intreq)
  2872.     rte
  2873.  
  2874. SetNeedChar:
  2875.     bset    #UNITB_NEEDCHAR,(UNIT_FLAGS,a3)
  2876. ;Important!!! We must call the normal interrupt routine because we can't be
  2877. ;sure that the interrupt was caused by us.
  2878.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2879.     move.l    (OldVec,pc),-(sp)
  2880.     rts
  2881.  
  2882. ReadErr:
  2883.     bra.b    RealReadErr
  2884.  
  2885. SignalRead:
  2886.     bclr    #MDUB_WaitingForChar,(MDU_FLAGS,a3)
  2887.     bset    #MDUB_CharAvailable,(MDU_FLAGS,a3)
  2888.     movem.l    d1/a1/a6,-(sp)
  2889.     move.l    (mdu_SysLib,a3),a6
  2890.     move.l    (readsig,a3),d0
  2891.     lea    (mdu_rtcb,a3),a1
  2892.     SYS    Signal    ;Signal the read task
  2893.     movem.l    (sp)+,d1/a1/a6
  2894.  
  2895.     btst    #ISRB_TDRE,d7
  2896.     bne    DoTDRE
  2897.  
  2898.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2899.     move.w    #$2000,(_custom+intreq)
  2900.     rte
  2901.  
  2902. DoneWriting:
  2903.  
  2904. ;    PUTDEBUG    75,<'%s/Int: Write signal.'>
  2905.  
  2906.     movem.l    d1/a1/a6,-(sp)
  2907.     move.l    (tdresig,a3),d0
  2908.     lea    (mdu_wtcb,a3),a1
  2909.     move.l    (mdu_SysLib,a3),a6
  2910.     SYS    Signal    ;Signal the write task
  2911.     movem.l    (sp)+,d1/a1/a6
  2912.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2913.     move.w    #$2000,(_custom+intreq)
  2914.     rte
  2915.  
  2916. ;Exceptional conditions handled here....
  2917.  
  2918. RealReadErr:
  2919.  
  2920. ;An exceptional condition occured - signal the read task
  2921.     movem.l    d1/a1/a6,-(sp)
  2922.     move.b    d7,(ISRcopy,a3)    ;Useful info
  2923.     move.b    (CSR,a5),(CSRcopy,a3) ;More useful info
  2924.     move.l    (readabortsig,a3),d0
  2925.     lea    (mdu_rtcb,a3),a1
  2926.     move.l    (mdu_SysLib,a3),a6
  2927.     SYS    Signal
  2928.     move.b    (RDR,a5),d0    ;This forces a clear of the error bits
  2929.     movem.l    (sp)+,d1/a1/a6
  2930.  
  2931.     btst    #ISRB_RDRF,d7    ;Test Receive Data Buffer Full
  2932.     bne    DoRDRF
  2933.     btst    #ISRB_TDRE,d7
  2934.     bne    DoTDRE
  2935.  
  2936.     movem.l    (sp)+,d0/d7/a0/a3/a5
  2937.     move.w    #$2000,(_custom+intreq)
  2938.     rte
  2939.  
  2940. ;********* End of fast interrupt routine *********
  2941.  
  2942. Int0000:    DoInt    0,0,0,0
  2943. Int0001:    DoInt    0,0,0,1
  2944. Int0010:    DoInt    0,0,1,0
  2945. Int0011:    DoInt    0,0,1,1
  2946. Int0100:    DoInt    0,1,0,0
  2947. Int0101:    DoInt    0,1,0,1
  2948. Int0110:    DoInt    0,1,1,0
  2949. Int0111:    DoInt    0,1,1,1
  2950. Int1000:    DoInt    1,0,0,0
  2951. Int1001:    DoInt    1,0,0,1
  2952. Int1010:    DoInt    1,0,1,0
  2953. Int1011:    DoInt    1,0,1,1
  2954. Int1100:    DoInt    1,1,0,0
  2955. Int1101:    DoInt    1,1,0,1
  2956. Int1110:    DoInt    1,1,1,0
  2957. Int1111:    DoInt    1,1,1,1
  2958.  
  2959.  
  2960.     ifne    INFO_LEVEL    ;If any debugging enabled at all
  2961.  
  2962. KPutFmt:    move.l    a2,-(sp)
  2963.     lea    (KPutChar,pc),a2
  2964.     bsr.b    KDoFmt
  2965.     move.l    (sp)+,a2
  2966.     rts
  2967.  
  2968. KDoFmt:    move.l    a6,-(sp)
  2969.     move.l    4,a6
  2970.     SYS    RawDoFmt
  2971.     move.l    (sp)+,a6
  2972.     rts
  2973.  
  2974. KPutChar:    move.l    a6,-(sp)
  2975.     move.l    4,a6
  2976.     SYS    RawPutChar
  2977.     move.l    (sp)+,a6
  2978.     rts
  2979.  
  2980.     endc
  2981.  
  2982. EndCode:
  2983.     end
  2984.